用于 uint32_t 和 size_t 的 printf 格式说明符

128

我有以下内容

size_t   i = 0;
uint32_t k = 0;

printf("i [ %lu ] k [ %u ]\n", i, k);

编译时我收到以下警告:

format ‘%lu’ expects type ‘long unsigned int’, but argument has type ‘uint32_t’

我在使用splint运行这个程序时得到了以下内容:

Format argument 1 to printf (%u) expects unsigned int gets size_t: k

非常感谢任何建议,


2
C89дёҚж”ҜжҢҒ<stdint.h>жҲ–<inttypes.h>дёӯзҡ„uint32_tзұ»еһӢпјӣеҰӮжһңжӮЁжғідҪҝз”Ёиҝҷдәӣзұ»еһӢпјҢеә”иҜҘеҚҮзә§еҲ°C89гҖӮдҪңдёәжү©еұ•пјҢеҫҲеҸҜиғҪGCCе…Ғи®ёжӮЁдҪҝз”Ёе®ғ们пјҢдҪҶжҳҜC89жІЎжңүд»»дҪ•жӯӨзұ»ж”ҜжҢҒгҖӮ - Jonathan Leffler
14
对于size_t类型,官方的C99格式修饰符是'z',例如 "%zu" - Jonathan Leffler
1
https://dev59.com/RXM_5IYBdhLWcg3wZSE6 - Ciro Santilli OurBigBook.com
我认为@kenny的答案对于uint32_t是最好的,但它缺少了size_t。@u0b34a0f6ae的答案包含了两者。 - jww
1
Jonathan Leffler在第一条评论中提到的C89应该改为C99。 - bph
4个回答

162

尝试

#include <inttypes.h>
...

printf("i [ %zu ] k [ %"PRIu32" ]\n", i, k);

z 表示与 size_t 长度相同的整数,而 PRIu32定义在 C99 头文件 inttypes.h表示无符号 32 位整数。


编译没有警告。但Splint不喜欢它。无法识别的格式代码:%zu。至于第二个错误,解析错误。(有关解析错误的帮助,请参见splint-help parseerrors。)***无法继续。 - ant2009
4
嘿,我建议你给splint提交一个缺陷报告。 - kennytm
11
这是正确答案。虽然我的个人建议是简单地投射,例如 printf("%lu", (unsigned long)i)。否则,由于类型更改,最终会在整个代码中出现大量警告。 - Dummy00001
1
这是正确的答案。我同意KennyTM关于为splint提交错误报告的建议。顺便说一下,"%zu"是size_t的正确格式。您不需要任何PRI*宏来打印size_t。 - R.. GitHub STOP HELPING ICE
1
如果我记得正确,%zu 是 C99 中的内容,在问题中他写的是“C89”。 - alcor
9
@alcor 是的,他确实使用了C89(显然是他正在使用的gcc编译器标志),但他使用的是uint32_t,所以实际上这是C99代码,应按照C99进行编译。 - Colin D Bennett

40
听起来你期望 size_tunsigned long 相同(可能是64位),实际上它是一个 unsigned int(32位)。在两种情况下都尝试使用 %zu
但我不是完全确定。

1
编译时没有警告。但是,运行splint我得到以下警告: 1)printf(%u)期望unsigned int得到uint32_t:i 2)printf(%u)期望unsigned int得到size_t:k - ant2009
听起来像是Splint太过苛求了。它可能会关注源代码中类型的名称,却没有意识到它们是等效的。我很想知道它对@KennyTM答案的反应是什么…… 它确实应该更具可移植性。 - Cogwheel
3
Splint正在执行正确的操作。只因为在您的编译器/平台上,int32_t恰好是int并不意味着在另一个编译器/平台上它不能是long。同样的,size_t也是如此。实际上,Splint正通过检测可移植性错误来进行更多的工作,因为容易、自然的检查方式只需遵循像编译器一样的类型定义。 - R.. GitHub STOP HELPING ICE
5
抱歉,它不具备可移植性。所需的只是格式说明符和类型相匹配,您始终可以转换来使其成立。long 至少为32位,因此 %lu(unsigned long)k 结合始终是正确的。size_t 更棘手,这就是为什么在 C99 中添加了 %zu 的原因。如果您无法使用它,则将其视为 klong 是 C89 中最大的类型,size_t 很可能不会更大)。 - u0b34a0f6ae

33

只需要确保格式说明符和类型匹配,你可以通过强制类型转换来实现。 long 至少是32位的,所以 %lu(unsigned long)k 一起使用始终是正确的:

所有需要的就是格式说明符和类型相匹配,您可以随时进行强制类型转换以使其成立。long 至少为32位,因此%lu(unsigned long) k 一起使用始终是正确的:

uint32_t k;
printf("%lu\n", (unsigned long)k);

size_t 在 C 语言中比较棘手,这就是为什么在 C99 中添加了 %zu 的原因。如果您无法使用它,那么请将其视为 k 来处理(在 C89 中,long 是最大的类型,size_t 很不可能更大)。

size_t sz;
printf("%zu\n", sz);  /* C99 version */
printf("%lu\n", (unsigned long)sz);  /* common C89 version */

如果您未正确为传递的类型设置格式说明符,则printf将执行读取数组中过多或过少的内存等效操作。只要使用显式转换来匹配类型,它就是可移植的。


20
如果您不想使用PRI*宏,打印任何整数类型的另一种方法是将其转换为intmax_tuintmax_t, 然后分别使用"%jd"%ju。这对于没有定义PRI*宏的POSIX(或其他操作系统)类型特别有用,例如off_t

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接