我有一个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打印。这在两种情况下都适用。我看看有没有其他的办法。
在程序员想要输出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)大的数字。
在程序员想要输出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)大的数字。
如果你想打印size_t的值作为字符串,你可以这样做:
char text[] = "Lets go fishing in stead of sitting on our but !!";
size_t line = 2337200120702199116;
/* on windows I64x or I64d others %lld or %llx if it works %zd or %zx */
printf("number: %I64d\n",*(size_t*)&text);
printf("text: %s\n",*(char(*)[])&line);
结果是:
号码:2337200120702199116
我们去钓鱼吧,别坐在椅子上了!
编辑:重新阅读问题,因为向下投票,我注意到他的问题不是%llu或%I64d,而是size_t类型在不同的机器上看到这个问题https://stackoverflow.com/a/918909/1755797
http://www.cplusplus.com/reference/cstdio/printf/
Size_t在32位机器上是unsigned long long int,在64位机器上是unsigned long long int
但是%ll总是期望一个unsigned long long int。
Size_t在不同的操作系统上的长度不同,而%llu是相同的
正如AraK所说,c++流接口将始终可移植地工作。
Std::size_t s = 1024;
Std::cout << s;//或任何其他类型的流,如stringstream!
如果你想要C stdio,对于某些“可移植”的情况,没有可移植的答案。正如您所看到的,选择错误的格式标志可能会产生编译器警告或给出不正确的输出,因此情况变得很糟糕。
C99试图用“%”PRIdMAX“\n”这样的inttypes.h格式来解决这个问题。但就像“%zu”一样,并不是所有人都支持c99(就像2013年之前的MSVS)。有“msinttypes.h”文件来处理这个问题。
If you cast to a different type, depending on flags you may get a compiler warning for truncation or a change of sign. If you go this route pick a larger relevant fixed size type. One of unsigned long long and "%llu" or unsigned long "%lu" should work, but llu may also slow things down in a 32bit world as excessively large. (Edit - my mac issues a warning in 64 bit for %llu not matching size_t, even though %lu, %llu, and size_t are all the same size. And %lu and %llu are not the same size on my MSVS2012. So you may need to cast + use a format that matches.)
因此,您可以使用固定大小的类型,例如int64_t。但是等等!现在我们回到了c99/c++11,旧的MSVS又失败了。另外,你也有类型转换(例如map.size()不是一个固定大小的类型)!
您可以使用第三方头文件或库,如boost。如果您还没有使用它,您可能不希望以这种方式扩展项目。如果您愿意为这个问题添加一个,为什么不使用c++流或条件编译呢?
所以你只能使用c++流、条件编译、第三方框架,或者恰好适合你的某种可移植的东西。