我有一个size_t类型的变量,我想使用printf()打印它。我使用什么格式说明符来可移植地打印它?

在32位机器中,%u似乎是正确的。我用g++ -g -W -Wall -Werror -ansi -pedantic编译,没有警告。但是当我在64位机器上编译该代码时,它会产生警告。

size_t x = <something>;
printf("size = %u\n", x);

warning: format '%u' expects type 'unsigned int', 
    but argument 2 has type 'long unsigned int'

如预期的那样,如果我将其更改为%lu,警告就会消失。

问题是,我如何编写代码,使它在32位和64位机器上编译警告免费?

编辑:作为一种变通方法,我猜一个答案可能是将变量“强制转换”为一个足够大的整数,比如unsigned long,然后使用%lu打印。这在两种情况下都适用。我看看有没有其他的办法。


当前回答

C99为此定义了“%zd”等。c++中没有可移植的格式说明符——你可以使用%p,这在这两种情况下都是word,但也不是一个可移植的选择,并以十六进制给出值。

或者,使用一些流(例如stringstream)或安全的printf替代品,如Boost Format。我知道这个建议只有有限的用途(并且确实需要c++)。(在实现unicode支持时,我们使用了适合我们需求的类似方法。)

C语言的基本问题是printf使用省省号在设计上是不安全的——它需要从已知参数中确定额外参数的大小,所以它不能被修复为支持“你得到的任何东西”。所以除非你的编译器实现了一些专有的扩展,否则你就不走运了。

其他回答

对于那些在c++中不一定支持C99扩展的人来说,我衷心推荐boost::format。这使得size_t类型的大小问题没有意义:

std::cout << boost::format("Sizeof(Var) is %d\n") % sizeof(Var);

由于在boost::格式中不需要大小说明符,所以只需考虑如何显示值即可。

printf("size = %zu\n", sizeof(thing) );

使用z修饰符:

size_t x = ...;
ssize_t y = ...;
printf("%zu\n", x);  // prints as unsigned decimal
printf("%zx\n", x);  // prints as hex
printf("%zd\n", y);  // prints as signed decimal

在程序员想要输出size_t的大多数上下文中,程序员对所输出的数值都有一个合理的上限。例如,如果一个程序员输出一个消息,说int的大小,使用:

printf("int is %u bytes", (unsigned)sizeof (int) );

从所有的实际目的来看,它与以下内容一样便携,但可能更快更小:

printf("int is %zu bytes", sizeof (int) );

这种构造可能失败的唯一情况是,在一个平台上,int上的填充字节数相对于unsigned int所能表示的最大值的大小大得离谱(sizeof (int)可能大于65535有点令人难以置信,但更令人难以置信的是,它可能这么大,而unsigned没有足够的值位来表示一个比sizeof (int)大的数字。

C99为此定义了“%zd”等。c++中没有可移植的格式说明符——你可以使用%p,这在这两种情况下都是word,但也不是一个可移植的选择,并以十六进制给出值。

或者,使用一些流(例如stringstream)或安全的printf替代品,如Boost Format。我知道这个建议只有有限的用途(并且确实需要c++)。(在实现unicode支持时,我们使用了适合我们需求的类似方法。)

C语言的基本问题是printf使用省省号在设计上是不安全的——它需要从已知参数中确定额外参数的大小,所以它不能被修复为支持“你得到的任何东西”。所以除非你的编译器实现了一些专有的扩展,否则你就不走运了。