用C ++清理代码到printf size_t(或者:在C ++中最接近C99的%z)

我有一些打印size_t C ++代码:

 size_t a; printf("%lu", a); 

我希望在32位和64位架构上编译时不会有任何警告。

如果这是C99,我可以使用printf("%z", a); 。 但是AFAICT %z不存在任何标准的C ++方言。 相反,我必须这样做

 printf("%lu", (unsigned long) a); 

这真的很丑。

如果没有内置的语言打印size_t的设施,我想知道是否可以编写一个printf包装器,或者是这样的,以便在size_t上插入适当的强制转换,从而消除虚假的编译器警告,同时保持良好的状态。

有任何想法吗?


编辑为了澄清为什么我使用printf:我有一个相对较大的代码库,我正在清理。 它使用printf包装来执行诸如“写入警告,将其logging到文件中,并可能退出错误代码”等。 我可能能够鼓起足够多的C ++ -foo来使用cout包装器来做到这一点,但是我宁愿不改变程序中的每一个warn()调用来摆脱一些编译器警告。

大多数编译器都有自己的size_tptrdiff_t参数的说明符,例如Visual C ++分别使用%Iu和%Id,我认为gcc将允许你使用%zu和%zd。

你可以创build一个macros:

 #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 

用法:

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

printf格式说明符%zu将在C ++系统上正常工作; 没有必要使它更复杂。

在windows和printf的Visual Studio实现

  %Iu 

为我工作。 看msdn

C ++ 11

C ++ 11导入C99所以std::printf应该支持C99 %zu格式说明符。

C ++ 98

在大多数平台上, size_tuintptr_t是等价的,在这种情况下,可以使用<cinttypes>定义的PRIuPTRmacros:

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

如果你真的想要安全,转换到uintmax_t并使用PRIuMAX

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

既然你使用的是C ++,为什么不使用IOStream呢? 这应该编译没有警告,并做正确的types意识的事情,只要你不使用大脑死亡的C + +实现,没有定义一个operator << size_t

当实际的输出必须用printf() ,你仍然可以把它与IOStreams结合起来,以获得types安全的行为:

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

它不是超高效的,但是你上面的情况处理文件I / O,所以这是你的瓶颈,而不是这个string格式化代码。

这是一个可能的解决scheme,但它不是一个漂亮的..

 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 ) ); 

基础size_t的有效types是依赖于实现的 。 C标准将其定义为sizeof运算符返回的types; 除了无符号和一种整型之外,size_t可以是任何大小可以容纳sizeof()返回的最大值的东西。

因此,用于size_t的格式string可能因服务器而异。 它应该总是有“你”,但可能是l或d或者别的什么东西…

一个技巧可能是将其转换为机器上最大的整数types,确保转换不会丢失,然后使用与此已知types关联的格式string。

C ++格式库为printf提供了一个快速的可移植(和安全的)实现,包括size_tz修饰符:

 #include "format.h" size_t a = 42; int main() { fmt::printf("%zu", a); } 

除此之外,它还支持类似Python的格式string语法,并捕获types信息,因此您不必手动提供它:

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

它已经过主要的编译器testing,并提供跨平台的一致输出。

免责声明 :我是这个图书馆的作者。