怎样才能打印一个size_tvariables可移植地使用printf家族?

我有一个size_ttypes的variables,我想用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位计算机上编译警告?

编辑:我想一个答案可能是“投”variables为unsigned long ,并打印使用%lu 。 这在两种情况下都会起作用。 我正在查看是否有任何其他的想法。

使用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 

看起来这取决于你使用的编译器(blech):

  • gnu表示%zu (或者%zx或者%zd但是显示它就好像它已经被签名一样)
  • 微软表示, %Iu (或%Ix ,或者%Id但又是签署的等等) – 但是从cl v19开始(在Visual Studio 2015中),Microsoft支持%zu (请参阅此评论的 回复 )

…当然,如果您使用的是C ++,您可以按照AraK的build议使用cout

对于C89,使用%lu并将值转换为unsigned long

 size_t foo; ... printf("foo = %lu\n", (unsigned long) foo); 

对于C99及更高版本,请使用%zu

 size_t foo; ... printf("foo = %zu\n", foo); 

延续Adam Rosenfield对Windows的回答。

我在VS2013 Update 4和VS2015预览版上testing了这个代码:

 // test.c #include <stdio.h> #include <BaseTsd.h> // see the note below int main() { size_t x = 1; SSIZE_T y = 2; printf("%zu\n", x); // prints as unsigned decimal printf("%zx\n", x); // prints as hex printf("%zd\n", y); // prints as signed decimal return 0; } 

VS2015生成二进制输出:

1
1
2

而由VS2013生成的那个说:


ZX
ZD

注意: ssize_t是一个POSIX扩展, SSIZE_T在Windows数据types中是相似的,因此我添加了<BaseTsd.h>引用。

另外,除了后面的C99 / C11头文件,所有的C99头文件都可以在VS2015预览版中使用:

 C11 - <stdalign.h> C11 - <stdatomic.h> C11 - <stdnoreturn.h> C99 - <tgmath.h> C11 - <threads.h> 

另外,C11的<uchar.h>现在包含在最新的预览中。

有关更多详细信息,请参阅旧的和新的标准符合性列表。

 std::size_t s = 1024; std::cout << s; // or any other kind of stream like stringstream! 

对于那些在C ++中做这个不一定支持C99扩展的人来说,我衷心推荐boost :: format。 这使size_ttypes的大小问题没有争议:

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

既然你不需要boost :: format中的大小说明符,你可以担心你想如何显示值。

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

如果您将32位无符号整数传递给%lu格式,它会警告您吗? 这应该没问题,因为转换是明确的,不会丢失任何信息。

我听说有些平台在<inttypes.h>中定义了可插入到格式string文字中的macros,但在Windows C ++编译器中看不到该标题,这意味着它可能不是跨平台的。

正如AraK所说,c ++stream接口总是可以工作的。

std :: size_t s = 1024; std :: cout << s; //或任何其他types的stream如stringstream!

如果你想要C stdio,对于某些“便携”的情况,没有可移植的答案。 如你所见,它会变得难看,select错误的格式标志可能会产生编译器警告或给出不正确的输出。

C99试图用inttypes.h格式解决这个问题,比如“%”PRIdMAX“\ n”。 但就像“%zu”一样,并不是每个人都支持c99(比如2013之前的MSVS)。 有“msinttypes.h”文件浮动以解决这个问题。

如果您转换为其他types,则根据标志,您可能会收到编译器警告,以便截断或更改符号。 如果你走这条路线,select一个更大的相关固定大小的types。 无符号long long和“%llu”或无符号long“%lu”应该是有效的,但llu也可能在32位世界中放慢速度。 (编辑 – 即使%lu,%llu和size_t都是相同的大小,我的mac在64位中发出警告,%llu与size_t不匹配,而%lu和%llu在我的MSVS2012上大小不一样。您可能需要投射+使用匹配的格式。)

对于这个问题,你可以使用固定大小的types,比如int64_t。 可是等等! 现在我们回到c99 / c ++ 11,而旧的MSVS再次失败。 另外你也有casts(例如map.size()不是一个固定大小的types)!

您可以使用第三方头或库,例如boost。 如果你还没有使用,你可能不想这样夸大项目。 如果您愿意为此问题添加一个,为什么不使用c ++stream或条件编译?

所以你可以使用c ++stream,条件编译,第三方框架,或者某种可移植的东西来为你工作。

C99为此定义了“%zd”等。 (感谢评论者)在C ++中没有可移植的格式说明符 – 你可以使用%p ,这两种情况都可以使用word,但不是一个可移植的选项,并以hex表示。

或者,使用一些stream(例如stringstream)或安全的printfreplace(如Boost格式) 。 我明白,这个build议只是有限的使用(并且需要C ++)。 (在实现unicode支持时,我们使用了符合我们需求的类似方法。)

C的基本问题是使用省略号的printf是不安全的 – 它需要根据已知的参数来确定额外参数的大小,所以不能固定来支持“你得到的东西”。 所以,除非你的编译器实现了一些专有的扩展,否则你运气不好。

在某些平台上,对于某些types,有特定的printf转换说明符可用,但有时候必须求助于更大的types。

我已经在这里logging了这个棘手的问题,例如代码: http : //www.pixelbeat.org/programming/gcc/int_types/并定期更新它的信息在新的平台和types。

如果你想打印一个size_t的值作为一个string,你可以这样做:

 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_ttypes在不同的机器上看到这个问题https://stackoverflow.com/a/918909/1755797
http://www.cplusplus.com/reference/cstdio/printf/

size_t在32位机器上是无符号整数,在64位上是unsigned long long int
但%ll总是期望一个无符号long long int。

size_t在不同的操作系统上长度不同,而%llu是相同的

 #ifndef _LP64 printf( "size = %u\n", x ); #else printf( "size = %lu\n", x ); #endif 

讨厌,但它的作品:)