我有一个 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位机器上编译警告?
编辑:我猜一个答案可能是将"cast"变量变成 unsigned long
,并使用 %lu
进行打印 . 这在两种情况下都有效 . 我在寻找是否还有其他想法 .
12 回答
对于那些谈论在C中做这个并不一定支持C99扩展的人,我衷心推荐boost :: format . 这使得size_t类型大小问题没有实际意义:
由于您不需要boost :: format中的大小说明符,因此您可以担心如何显示该值 .
使用
z
修饰符:看起来它取决于您正在使用的编译器(blech):
gnu says %zu(或
%zx
,或%zd
,但显示它就像签名一样,等等)Microsoft says %Iu(或
%Ix
,或%Id
但又签名等) - 但从cl v19开始(在Visual Studio 2015中),Microsoft支持%zu
(参见this reply至this comment)...当然,如果您使用的是C,则可以使用
cout
代替suggested by AraK .对于C89,使用
%lu
并将值转换为unsigned long
:对于C99及更高版本,请使用
%zu
:扩展Adam Rosenfield对Windows的回答 .
我在VS2013 Update 4和VS2015预览版上测试了这段代码:
VS2015生成二进制输出:
而由VS2013生成的那个说:
注意:
ssize_t
是POSIX扩展,SSIZE_T
在Windows Data Types中类似,因此我添加了<BaseTsd.h>
参考 .此外,除了以下C99 / C11标头外,所有C99标头都可在VS2015预览中使用:
此外,C11的
<uchar.h>
现已包含在最新预览中 .有关更多详细信息,请参阅此old和new列表以获取标准一致性 .
正如AraK所说,c stream接口将始终可移植 .
如果你想要C stdio,对于某些“便携式”的情况,没有可解决的问题 . 它变得丑陋,因为你看到,选择错误的格式标志可能会产生编译器警告或提供不正确的输出 .
C99试图用inttypes.h格式解决这个问题,比如“%”PRIdMAX“\ n” . 但就像“%zu”一样,并非所有人都支持c99(如2013年之前的MSVS) . 有“msinttypes.h”文件浮动来处理这个问题 .
如果您转换为其他类型,根据标志,您可能会收到编译器警告,要求截断或更改符号 . 如果你走这条路线,选择一个更大的相关固定尺寸类型 . 一个无符号长long和“%llu”或无符号长“%lu”应该可以工作,但是llu也可能会减慢32位世界中的速度 . (编辑 - 我的mac发出64位警告,因为%llu不匹配size_t,即使%lu,%llu和size_t都是相同的大小 . %lu和%llu在我的MSVS2012上的大小不同 . 所以你可能需要使用匹配的格式 . )
就此而言,您可以使用固定大小类型,例如int64_t . 可是等等!现在我们回到c99 / c 11,旧的MSVS再次失败 . 另外你还有强制转换(例如map.size()不是固定大小的类型)!
您可以使用第三方 Headers 或库,例如boost . 如果您还没有使用过,那么您可能不希望以这种方式对项目进行膨胀 . 如果您愿意为此问题添加一个,为什么不使用c流或条件编译?
因此,您需要使用c流,条件编译,第三方框架或适合您的便携式设备 .
如果将32位无符号整数传递给%lu格式,它会警告你吗?它应该没问题,因为转换是明确定义的,不会丢失任何信息 .
我听说有些平台在
<inttypes.h>
中定义了宏,你可以插入到格式字符串文字中,但我在Windows C编译器上看不到那个 Headers ,这意味着它可能不是跨平台的 .C99为此定义了"%zd"等 . (感谢评论者)C中没有可移植格式说明符 - 你可以使用
%p
,这两个场景中的woulkd字,但也不是便携式选择,并以十六进制给出值 .或者,使用一些流式传输(例如串流)或安全的printf替换,例如Boost Format . 据我所知,这个建议仅限于使用(并且需要C) . (我们已经在实现unicode支持时,我们使用了类似的方法来满足我们的需求 . )
C的基本问题是使用省略号的printf在设计上是不安全的 - 它需要根据已知参数确定附加参数的大小,因此无法修复它以支持“无论你得到什么” . 因此,除非您的编译器实现某些专有扩展,否则您运气不佳 .
在某些平台上,对于某些类型,有特定的printf转换说明符可用,但有时必须使用转换为更大的类型 .
我在这里记录了这个棘手的问题,使用示例代码:http://www.pixelbeat.org/programming/gcc/int_types/并定期更新新平台和类型的信息 .
如果要将size_t的值打印为字符串,可以执行以下操作:
结果是:
号码:2337200120702199116
文字:让我们去钓鱼,而不是坐在我们身上!
编辑:重新阅读问题因为投票结果我注意到他的问题不是%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是相同的