Clean code to printf size_t in C++ (or: Nearest equivalent of C99's %z in C++)

。_饼干妹妹 提交于 2019-11-28 03:25:44
dalle

Most compilers have their own specifier for size_t and ptrdiff_t arguments, Visual C++ for instance use %Iu and %Id respectively, I think that gcc will allow you to use %zu and %zd.

You could create a macro:

#if defined(_MSC_VER) || defined(__MINGW32__) //__MINGW32__ should goes before __GNUC__
  #define JL_SIZE_T_SPECIFIER    "%Iu"
  #define JL_SSIZE_T_SPECIFIER   "%Id"
  #define JL_PTRDIFF_T_SPECIFIER "%Id"
#elif defined(__GNUC__)
  #define JL_SIZE_T_SPECIFIER    "%zu"
  #define JL_SSIZE_T_SPECIFIER   "%zd"
  #define JL_PTRDIFF_T_SPECIFIER "%zd"
#else
  // TODO figure out which to use.
  #if NUMBITS == 32
    #define JL_SIZE_T_SPECIFIER    something_unsigned
    #define JL_SSIZE_T_SPECIFIER   something_signed
    #define JL_PTRDIFF_T_SPECIFIER something_signed
  #else
    #define JL_SIZE_T_SPECIFIER    something_bigger_unsigned
    #define JL_SSIZE_T_SPECIFIER   something_bigger_signed
    #define JL_PTRDIFF_T_SPECIFIER something-bigger_signed
  #endif
#endif

Usage:

size_t a;
printf(JL_SIZE_T_SPECIFIER, a);
printf("The size of a is " JL_SIZE_T_SPECIFIER " bytes", a);

The printf format specifier %zu will work fine on C++ systems; there is no need to make it more complicated.

C++11

C++11 imports C99 so std::printf should support the C99 %zu format specifier.

C++98

On most platforms, size_t and uintptr_t are equivalent, in which case you can use the PRIuPTR macro defined in <cinttypes>:

size_t a = 42;
printf("If the answer is %" PRIuPTR " then what is the question?\n", a);

If you really want to be safe, cast to uintmax_t and use PRIuMAX:

printf("If the answer is %" PRIuMAX " then what is the question?\n", static_cast<uintmax_t>(a));
meissnersd

On windows and the Visual Studio implementation of printf

 %Iu

works for me. see msdn

Since you're using C++, why not use IOStreams? That should compile without warnings and do the right type-aware thing, as long as you're not using a brain-dead C++ implementation that doesn't define an operator << for size_t.

When the actual output has to be done with printf(), you can still combine it with IOStreams to get type-safe behavior:

size_t foo = bar;
ostringstream os;
os << foo;
printf("%s", os.str().c_str());

It's not super-efficient, but your case above deals with file I/O, so that's your bottleneck, not this string formatting code.

here's a possible solution, but it's not quite a pretty one..

template< class T >
struct GetPrintfID
{
  static const char* id;
};

template< class T >
const char* GetPrintfID< T >::id = "%u";


template<>
struct GetPrintfID< unsigned long long > //or whatever the 64bit unsigned is called..
{
  static const char* id;
};

const char* GetPrintfID< unsigned long long >::id = "%lu";

//should be repeated for any type size_t can ever have


printf( GetPrintfID< size_t >::id, sizeof( x ) );

The effective type underlying size_t is implementation dependent. C Standard defines it as the type returned by the sizeof operator; aside from being unsigned and a sort of integral type, the size_t can be pretty much anything which size can accommodate the biggest value expected to be returned by sizeof().

Consequently the format string to be used for a size_t may vary depending on the server. It should always have the "u", but may be l or d or maybe something else...

A trick could be to cast it to the biggest integral type on the machine, ensuring no loss in the conversion, and then using the format string associated with this known type.

The C++ Format library provides a fast portable (and safe) implementation of printf including the z modifier for size_t:

#include "format.h"

size_t a = 42;

int main() {
  fmt::printf("%zu", a);
}

In addition to that it supports Python-like format string syntax and captures type information so that you don't have to provide it manually:

fmt::print("{}", a);

It has been tested with major compilers and provides consistent output across platforms.

Disclaimer: I'm the author of this library.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!