我有一个类型为size_t的变量,我想用printf()打印它。我使用什么格式说明符可以方便地打印它?
在32位机器中,%u似乎是正确的。我用g++ -g -W -Wall -Werror -ansi -pedantic编译,没有任何警告。但当我在64位机器上编译代码时,它会产生警告。
1 2 3 4 5 6
| size_t x = <something >;
printf("size = %u
", x );
warning : format '%u' expects type 'unsigned int',
but argument 2 has type 'long unsigned int' |
如果我把它改成%lu,警告就会消失。
问题是,我如何编写代码,以便在32位和64位机器上都编译无警告的代码?
编辑:作为一种解决方法,我想一个答案可能是将变量"强制转换"成足够大的整数,比如说unsigned long,然后使用%lu打印。这两种情况都适用。我在看是否还有其他想法。
- 如果您的libc实现不支持z修饰符,那么强制转换到unsigned long是最好的选择;c99标准建议size_t不具有大于long的整数转换秩,因此您相当安全。
- 可能与平台无关的大小格式说明符在C中重复?
- 使用printf打印尺寸的正确方法是什么?
- 类型大小的变量可能重复跨平台格式字符串?
- 在Windows平台上,大小不能大于长。出于兼容性的原因,long总是32位的,但大小不能是64位的。因此,强制转换为无符号长可能会丢失一半位。对不起:-)
- 可能是使用printf打印尺寸的正确方法的副本?
使用z修改器:
1 2 3 4 5 6 7 8
| size_t x = ... ;
ssize_t y = ... ;
printf("%zu
", x ); // prints as unsigned decimal
printf("%zx
", x ); // prints as hex
printf("%zd
", y ); // prints as signed decimal |
- + 1。这是C99加法,还是同样适用于C++(我没有C90手提)?
- 我相信这是一个C99的添加,见&167;7.19.6.1.7。还有intmax_t和ptrdiff_t的j和t。
- 这是一个C99的添加,并没有显示在2009年11月09日的C++ 0x草案的EDCOX1×33长度修饰符列表中(第672页表84)。
- @克里斯托夫:最新的草案N3035也没有。
- @avakar@adam rosenfield@christoph@gman:然而,在N3035&167;1.2规范性引用文件中,仅引用了C99标准,并且&167;17.6.1.2/3的相同状态"提供了C标准库的设施"。我将解释为,除非另有规定,否则C99标准库中的所有内容都是C标准库的一部分。++0x标准库,包括c99中的其他格式说明符。
- @Christoph,z不需要在表84中指定。该表不是对printf可用格式的描述,而只是从基本类型到printf标志的映射。因为流是类型安全的,所以您不需要告诉他们您打印了一个size_t,他们会自动计算出当一个ulong或ulong long等。打印。
- 原谅我迟到了。我尝试了"%ZU"。只要我不在编译中使用"—学究式的",就可以了。当我包含这个时,错误是:ISO C++不支持"z"GuuuPrimTf长度修饰符。我在Solaris上运行gcc 4.4.1版。有什么想法吗?
- @ ArunSaha:它只是C99的一个特性,而不是C++。如果你想用EDCOX1(7)来编译它,你需要得到一个支持C++ 1x草稿(非常不可能)的编译器,或者你需要把你的代码移到一个编译为C99的文件中。否则,您唯一的选择是将变量强制转换为unsigned long long,并使用%llu实现最大的可移植性。
- @亚当·罗森菲尔德:谢谢。
- %zu不适用于Windows
- @ L?紫外线?nhph&250;c无论%zu是否工作,都是编译器和(特别是)库的函数,而不是操作系统的函数。在GCC4.8.3和Cygwin1.7.32(newlib)附带的库中,它对我来说很好。
- @我知道这取决于编译器使用的标准lib,但是现在编辑太晚了。此外,它不适用于mingw/mingw64 gcc。Cygwin使用一个库来模拟Unix函数,因此显然它应该可以工作。
- 您应该添加一个指向参考的链接,比如gnu.org/software/libc/manual/html_node/&hellip;
- 虽然GCC4.3.3确实支持C99,但在Solaris 8中,%zu和%zu都不能为我工作——只能使用%u。此外,对于Sun Workshop,仅从6.2版(2001年7月)起支持C99。
- MSVC仍然不完全支持C99:此解决方案仅适用于类似GNU的编译器
- @Adam Rosenfield:Visual Studio 2015最终支持%zu
- warning: unknown conversion type character 'z' in format [-Wformat=]
- @Adamrosenfield在第2行中的OD代码-不存在ssize,我认为这只是一个打字错误。
- Z部分是一个长度说明符,表示参数的长度将是大小T。(来源:stackoverflow.com/q/940087/2780334)
看起来它取决于您使用的编译器(Blech)的不同:
- GNU说%zu(或者%zx,或者%zd,但是显示的好像是签名的,等等。)
- 微软说%Iu(或%Ix,或%Id,但还是签了名,等等);但是从cl v19(在Visual Studio 2015中)起,微软支持%zu(请参阅此评论的回复)
当然,如果你使用C++,你可以使用AraK所建议的EDCOX1 8。
- newlib(即cygwin)也支持z。
- %zd对于size_t是不正确的;对于size_t对应的有符号类型是正确的,但size_t本身是无符号类型。
- @基思汤普森:我也提到了%zu,以东x1(15),以防他们想要十六进制。确实,%zu应该是名单上的第一位。固定的。
- @T.J.克劳德:我认为%zd根本不应该在名单上。我想不出任何理由用%zd而不是%zu来打印size_t值。如果值超过SIZE_MAX / 2,它甚至无效(具有未定义的行为)。(为了完整起见,您可能会提到八进制的%zo。
- Lol %Iu。微软再一次用自己的方式来做,而不仅仅是坚持标准。直到2013年,他们才最终包括了一些C99功能。但我相信他们的决定是有正当理由的。毕竟他们的程序员比其他人都聪明。PPPPP
- 非常感谢您提到微软使用了其他东西
- @这种类型在posix上称为ssize_t。
- @fuzzxl:posix不要求ssize_t是对应size_t的有符号类型,因此不能保证与"%zd"匹配。(可能在大多数实现中)pubs.opengroup.org/onlinepubs/9699919799/basedefs/&hellip;
对于C89,使用%lu,并将值转换为unsigned long:
1 2 3 4
| size_t foo ;
...
printf("foo = %lu
", (unsigned long) foo ); |
对于C99及更高版本,使用%zu:
1 2 3 4
| size_t foo ;
...
printf("foo = %zu
", foo ); |
- 考虑到2013年,建议"适用于C99及更高版本"以及"适用于C99之前版本"。最佳答案。
- 不要这样做。它将在64位窗口上失败,其中大小为64位,长度为32位。
- @那么64位Windows的答案是什么呢?
- @约翰伯德也许是埃多克斯1〔8〕?
- 或者:您可以强制转换到uint64_t,然后使用inttypes.h中的PRIu64宏,该宏包含格式说明符。
- @Jamesko这有什么意义?uint64_t是c99,所以如果它是可用的,那么"%zu"也是可用的(这是正确的方法)。
- yttrill @:它只会失败,如果numerical value被印刷exceeds ulong _最大。事实上,价值也size_t型的方式在没有implies ITS可以represent大numerical价值的数量。例如,像是printf("Ints take %u bytes.
", (unsigned)sizeof (int);能在失败的hypothetical平台在int腹部比更高的padding万位,但realistically speaklng有会是没有利用到outputting型的大unsigned比,无论大size_t可能。
延伸到亚当·罗森菲尔德对Windows的回答。
我在VS2013更新4和VS2015预览版上测试了此代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| // test.c
#include <stdio.h>
#include <BaseTsd.h> // see the note below
int main ()
{
size_t x = 1;
SSIZE_T y = 2;
printf("%zu
", x ); // prints as unsigned decimal
printf("%zx
", x ); // prints as hex
printf("%zd
", y ); // prints as signed decimal
return 0;
} |
VS2015生成的二进制输出:
1
1
2
而由VS2013生成的报告说:
zu
zx
zd
注:ssize_t是posix扩展,ssize_t在windows数据类型中是类似的,所以我增加了引用。
此外,除了以下C99/C11标题外,所有C99标题都可在VS2015预览版中使用:
1 2 3 4 5
| C11 - <stdalign.h>
C11 - <stdatomic.h>
C11 - <stdnoreturn.h>
C99 - <tgmath.h>
C11 - <threads.h> |
此外,C11的现在包含在最新预览中。
有关更多详细信息,请参阅此标准一致性的新旧列表。
- vs2013更新产生相同的结果的5号更新4给了你。
对于那些在C++中讨论这不一定支持C99扩展的人,我衷心地推荐Booo::格式。这使得"大小"类型的大小问题变得不重要:
1 2
| std::cout << boost::format("Sizeof(Var) is %d
") % sizeof(Var); |
因为您不需要Boost::格式的大小说明符,所以您只需担心如何显示该值。
- 可能要%u然后。
- 面向对象的程序设计。你是的,当然,是的先生。
1 2
| std::size_t s = 1024;
std::cout << s; // or any other kind of stream like stringstream! |
- 有"C++"标签。我认为这是C++中最好的方法:
- 是的,但是发问者特别要求一个printf说明符。我想他们还有其他一些未声明的限制,使得使用std::cout成为一个问题。
- @ DoAL我想知道C++流在C++项目中会产生什么样的问题!
- @ AraK。他们很慢?他们添加了很多字节,原因不多。阿伦萨只是想知道他/她自己的个人知识?个人偏好(我更喜欢stdio而不是fstream本人)。原因很多。
- 1流绝对是C++的方式。
- @唐纳:事实上,当阿拉克发表他的答案时,这个问题并没有明确地说他想使用printf。他说他想输出这个值,他用了一个printf的例子,但门是开着的……:-)问题已经澄清。
- @ T.K.Cuuld:嗯,原来的请求确实说需要一个C解决方案(通过标签),并且有很好的理由在C++中不使用流,例如,如果输出格式描述符是从消息目录中拉过来的。(如果需要,您可以为消息编写一个解析器,并使用流,但是当您可以利用现有的代码时,这是一项很大的工作。)
- @多纳:标签是C和C++。我没有任何方式支持C++的I/O流的东西(我不是它的粉丝),只是指出这个问题并不是最初的"……请询问EDOCX1·3"说明符的规范。
1 2
| printf("size = %zu
", sizeof(thing ) ); |
正如AraK所说,C++流接口总是可以移植的。
std::size_t s = 1024;
std::cout << s; // or any other kind of stream like stringstream!
如果您想要c stdio,对于某些情况下的"可移植"就没有可移植的答案了。正如您所看到的,选择错误的格式标志可能会产生一个编译器警告或给出错误的输出。
C99试图用inttypes.h格式解决这个问题,比如"%"pridmax""。但正如"zu"一样,并非所有人都支持C99(如2013年之前的MSV)。有一些"msinttypes.h"文件可以处理这个问题。
如果强制转换为其他类型,根据标志的不同,可能会收到编译器关于截断或符号更改的警告。如果你走这条路线,选择一个更大的相关固定尺寸类型。unsigned long long和"%llu"或unsigned long"%lu"中的一个应该可以工作,但在32位的世界中,llu也可能会使速度变慢,因为它太大。(编辑-我的Mac会以64位发出一条警告,警告%llu与大小不匹配,即使%lu、%llu和大小都相同。和%lu和%llu在我的MSVS2012上的大小不同。因此,您可能需要强制转换+使用匹配的格式。)
为此,您可以使用固定大小的类型,如int64_t。但请稍候!现在我们回到C99/C++ 11,旧的MSV又失败了。此外,您还具有强制转换(例如map.size()不是固定大小类型)!
您可以使用第三方头或库,如boost。如果你还没有使用,你可能不想这样夸大你的项目。如果您愿意为这个问题添加一个,为什么不使用C++流或条件编译?
因此,你要面对C++流、条件编译、第三方框架或者一些适合你的便携式工具。
如果将32位无符号整数传递到%lu格式,它会警告您吗?它应该是好的,因为转换是定义良好的,并且不会丢失任何信息。
我听说有些平台在EDCOX1 0中定义宏,可以插入到格式字符串文字中,但是我在Windows C++编译器上没有看到这个标题,这意味着它可能不是跨平台的。
- 如果您向printf传递了错误大小的内容,大多数编译器都不会警告您。GCC是一个例外。inttypes.h是在c99中定义的,所以任何符合c99的c编译器都将拥有它,到目前为止,这应该是所有编译器。不过,您可能需要使用编译器标志打开C99。在任何情况下,intttypes.h都不会为size_t或ptrdiff_t定义特定的格式,因为它们被认为足够重要,可以分别获得自己的大小说明符"z"和"t"。
- 如果使用%lu,则应将size_t值强制转换为unsigned long。对printf的论据没有隐含的转换(升职除外)。
C99为此定义了"%zd"等。(感谢评论家)C++中没有可移植格式的说明符,你可以使用EDCOX1,10,这两个场景中的单词,但也不是便携式的选择,并给出了十六进制的值。
或者,使用一些流媒体(如Stringstream)或安全的printf替换,如boost格式。我理解这个建议只是有限的使用(并且确实需要C++)。(在实现Unicode支持时,我们使用了适合我们需要的类似方法。)
C的基本问题是,使用省略号的printf在设计上是不安全的-它需要根据已知的参数来确定附加参数的大小,因此不能修复它来支持"您得到的任何东西"。所以,除非您的编译器实现了一些专有扩展,否则您不走运。
- EDCOX1×0的大小修改器是标准C,但是由于各种原因,一些LIBC实现被困在1990中(如微软基本上放弃了C,而不是C++),而更为新近的是C。
- c99将大小说明符"z"定义为大小t值的大小,"t"定义为ptrdiff值的大小。
- 谢谢你的评论,我已经把它写在回复中了。
- %zd是错误的,它是无符号的,所以应该是%zu。
在某些平台和某些类型上,有特定的printf转换说明符可用,但有时必须使用强制转换到较大的类型。
我在这里用示例代码记录了这个棘手的问题:http://www.pixelbeat.org/programming/gcc/int_类型/并定期更新新平台和类型的信息。
- 注意,链接-唯一的回答是discouraged,所以回答应该最后点的搜索,为解决方案(vs。然而另一个stopover of references,这tend得到stale推移)。请考虑添加的单机synopsis睾丸,保持同步的链接作为参考。
如果要将大小的值打印为字符串,可以执行以下操作:
1 2 3 4 5 6 7 8
| 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
",*(size_t*)&text );
printf("text: %s
",*(char(*)[])&line ); |
结果是:
编号:2337200120702199116
我们去钓鱼吧,而不是坐在我们的船上。!
编辑:由于投票数下降,重新阅读问题。我注意到他的问题不是%llu或%i64d,而是不同机器上的大小类型。请参阅此问题https://stackoverflow.com/a/918909/1755797http://www.cplusplus.com/reference/cstio/printf/
在32位机器上,大小为unsigned int,在64位机器上,大小为unsigned long int。但是%ll总是需要一个无符号长整型int。
大小在不同操作系统上的长度不同,而%llu相同
- 我当然要来这吗?!!!!!!
- 铸造第一8字节的字符到阵列的unsigned长长的64bit通过尺寸_ T的指针和打印他们的个数与printf % i64d是不是真的spectacular我知道,当然我不在T代码到预防型溢出,但这是不在scope"的问题。