我有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
进行打印。这在两种情况下都有效。我在寻找是否还有其他想法。
答案 0 :(得分:416)
使用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
答案 1 :(得分:80)
看起来它取决于您正在使用的编译器(blech):
%zu
(或%zx
或%zd
,但会将其显示为已签名等。)%Iu
(或%Ix
或%Id
但又签名等等) - 但从cl v19开始(在Visual Studio 2015中),Microsoft支持%zu
(请参阅this reply至this comment) ...当然,如果您使用的是C ++,则可以使用cout
代替suggested by AraK。
答案 2 :(得分:57)
对于C89,请使用%lu
并将值转换为unsigned long
:
size_t foo;
...
printf("foo = %lu\n", (unsigned long) foo);
对于C99及更高版本,请使用%zu
:
size_t foo;
...
printf("foo = %zu\n", foo);
答案 3 :(得分:9)
扩展Adam Rosenfield对Windows的回答。
我在VS2013 Update 4和VS2015预览中测试了这段代码:
// 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 Data Types中类似,因此我添加了<BaseTsd.h>
引用。
此外,除了以下C99 / C11标题外,VS2015预览版中还提供了所有C99标题:
C11 - <stdalign.h>
C11 - <stdatomic.h>
C11 - <stdnoreturn.h>
C99 - <tgmath.h>
C11 - <threads.h>
此外,C11&#39; <uchar.h>
现已包含在最新预览中。
答案 4 :(得分:5)
printf("size = %zu\n", sizeof(thing) );
答案 5 :(得分:5)
std::size_t s = 1024;
std::cout << s; // or any other kind of stream like stringstream!
答案 6 :(得分:5)
对于那些在C ++中执行此操作而不一定支持C99扩展的人,我衷心推荐boost :: format。这使得size_t类型大小问题没有问题:
std::cout << boost::format("Sizeof(Var) is %d\n") % sizeof(Var);
由于您不需要boost :: format中的大小说明符,您可以担心如何显示该值。
答案 7 :(得分:2)
正如AraK所说,c ++流接口总是可以移植。
std :: size_t s = 1024; std :: cout&lt;&lt; S; //或者像stringstream一样的任何其他类型的流!
如果你想要C stdio,对于某些便携式的病例,没有便携式答案。&#34;它变得很难看,因为你已经看到,选择错误的格式标志可能会产生编译器警告或输出错误。
C99试图用inttypes.h格式来解决这个问题,例如&#34;%&#34; PRIdMAX&#34; \ n&#34;。但就像&#34;%zu&#34;一样,并非所有人都支持c99(如2013年之前的MSVS)。有&#34; msinttypes.h&#34;浮动的文件来处理这个。
如果您转换为其他类型,根据标记,您可能会收到编译器警告,要求截断或更改符号。如果你走这条路线,选择一个更大的相关固定尺寸类型。一个unsigned long long和&#34;%llu&#34;或未签名的长期&#34;%lu&#34;应该工作,但llu也可能减慢32位世界的速度,因为它过大。 (编辑 - 我的mac发出64位警告,因为%llu不匹配size_t,即使%lu,%llu和size_t都是相同的大小。%lu和%llu在我的MSVS2012上的大小不同。所以你可能需要施放+使用匹配的格式。)
就此而言,您可以使用固定大小的类型,例如int64_t。可是等等!现在我们回到c99 / c ++ 11,旧的MSVS再次失败。另外你还有演员表(例如map.size()不是固定大小的类型)!
您可以使用第三方标题或库,例如boost。如果您还没有使用过,那么您可能不希望以这种方式给项目充气。如果您愿意为此问题添加一个,为什么不使用c ++流或条件编译?
因此,您需要了解c ++流,条件编译,第三方框架或适合您的便携式设备。
答案 8 :(得分:1)
在任何合理的现代 C 实现中,"%zu"
是打印 size_t
类型值的正确方法:
printf("sizeof (int) = %zu\n", sizeof (int));
"%zu"
格式说明符已添加到 1999 年 ISO C 标准中(并被 2011 年 ISO C++ 标准采用)。如果您不需要担心更早的实现,现在可以停止阅读。
如果您的代码需要可移植到 C99 之前的实现,您可以将该值转换为 unsigned long
并使用 "%lu"
:
printf("sizeof (int) = %lu\n", (unsigned long)sizeof (int));
这不能移植到 C99 或更高版本,因为 C99 引入了 long long
和 unsigned long long
,因此 size_t
可能比 unsigned long
更宽。
抵制在没有演员表的情况下使用 "%lu"
或 "%llu"
的诱惑。用于实现 size_t
的类型是实现定义的,如果类型不匹配,则行为未定义。像 printf("%lu\n", sizeof (int));
这样的东西可能“有效”,但它根本不便携。
原则上,以下内容应该涵盖所有可能的情况:
#if __STDC_VERSION__ < 199901L
printf("sizeof (int) = %lu\n", (unsigned long)sizeof (int));
#else
printf("sizeof (int) = %zu\n", sizeof (int));
#endif
在实践中,它可能并不总是正常工作。 __STD_VERSION__ >= 199901L
应该保证支持 "%zu"
,但并非所有实现都必须正确,特别是因为 __STD_VERSION__
是由编译器设置的,而 "%zu"
是由运行时库实现。例如,具有部分 C99 支持的实现可能会实现 long long
并使 size_t
成为 unsigned long long
的 typedef,但不支持 "%zu"
。 (这样的实现可能不会定义 __STDC_VERSION__
。)
有人指出,Microsoft 的实现可以有 32 位 unsigned long
和 64 位 size_t
。 Microsoft 确实支持 "%zu"
,但该支持添加的相对较晚。另一方面,只有当特定的 unsigned long
值碰巧超过 size_t
时,转换为 ULONG_MAX
才会有问题,这在实践中不太可能发生。
如果您能够假设合理的现代实现,只需使用 "%zu"
。如果您需要允许较旧的实现,这里有一个适用于各种配置的可移植的荒谬程序:
#include <stdio.h>
#include <limits.h>
int main(void) {
const size_t size = -1; /* largest value of type size_t */
#if __STDC_VERSION__ < 199901L
if (size > ULONG_MAX) {
printf("size is too big to print\n");
}
else {
printf("old: size = %lu\n", (unsigned long)size);
}
#else
printf("new: size = %zu\n", size);
#endif
return 0;
}
打印“尺寸太大而无法打印”的一种实现(Windows/Cygwin 上的 x86_64-w64-mingw32-gcc.exe -std=c90
)实际上支持 unsigned long long
作为 C90 之上的扩展,因此您可以利用那 - 但我可以想象一个支持 unsigned long long
但不支持 "%llu"
的 C99 之前的实现。而且该实现无论如何都支持 "%zu"
。
根据我的经验,当我探索实现时,我只想在快速一次性代码中打印 size_t
值,而不是在生产代码中。在这种情况下,做任何有效的事情可能就足够了。
(问题是关于 C,但我会提到在 C++ 中,std::cout << sizeof (int)
将在任何版本的语言中正常工作。)
答案 9 :(得分:0)
如果您将32位无符号整数传递给%lu格式,它会警告您吗?它应该没问题,因为转换是明确定义的,不会丢失任何信息。
我听说有些平台在<inttypes.h>
中定义了你可以插入到格式字符串文字中的宏但我在Windows C ++编译器上看不到那个标题,这意味着它可能不是跨平台的
答案 10 :(得分:0)
在程序员想要输出 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)
的数字,它可能会那么大。
答案 11 :(得分:-1)
C99为此定义了“%zd”等。 (感谢评论者)在C ++中没有可移植的格式说明符 - 你可以使用%p
,这两个场景中的单词是woulkd,但也不是便携式选择,并以十六进制给出值。
或者,使用一些流式传输(例如stringstream)或安全的printf替换,例如Boost Format。据我所知,这个建议仅限于使用(并且需要C ++)。 (在实现unicode支持时,我们使用了类似的方法来满足我们的需求。)
C的基本问题是使用省略号的printf在设计上是不安全的 - 它需要根据已知参数确定附加参数的大小,因此无法修复它以支持“无论你得到什么”。因此,除非你的编译器实现一些专有扩展,否则你运气不好。
答案 12 :(得分:-3)
在某些平台上,对于某些类型,有特定的printf转换说明符可用,但有时候必须使用强制转换为更大的类型。
我在这里记录了这个棘手的问题,示例代码: http://www.pixelbeat.org/programming/gcc/int_types/ 并定期更新新平台和类型的信息。
答案 13 :(得分:-5)
如果要将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
text:让我们去钓鱼,而不是坐在我们身边!
编辑:重新阅读问题因为投票结果我注意到他的问题不是%llu或%I64d但是不同机器上的size_t类型看到了这个问题https://stackoverflow.com/a/918909/1755797
http://www.cplusplus.com/reference/cstdio/printf/
size_t在32位机器上是unsigned int,在64位机器上是unsigned long long int 但是%ll总是需要一个unsigned long long int。
size_t在不同操作系统上的长度不同,而%llu是相同的