为啥使用 C printf 格式“%#x”打印 0(零)而没有前导“0x”?
Posted
技术标签:
【中文标题】为啥使用 C printf 格式“%#x”打印 0(零)而没有前导“0x”?【英文标题】:Why is 0 (zero) printed without leading "0x" with C printf format "%#x"?为什么使用 C printf 格式“%#x”打印 0(零)而没有前导“0x”? 【发布时间】:2012-01-20 17:46:10 【问题描述】:背景:我有许多脚本通过查找前导“0x”来解析日志文件以查找十六进制数字。我们的嵌入式 C 库更改为新的 printf。新的 printf 比我们以前的标准更符合标准,而且我的脚本坏了。
在 Linux 机器上:
#include <stdio.h>
int main( void )
printf( "%#010x\n", 0 );
printf( "%#010x\n", 1 );
return 0;
输出(使用 glibc)是:
0000000000
0x00000001
我们固件的输出是:
0x00000000
0x00000001
从 printf(3) 开始,在 '#' 标志字符上: “对于 x 和 X 转换,非零结果的前面带有字符串“0x”(或 X 转换的“0X”)。”
我很好奇为什么。无需深入研究 C 标准文档或为标准委员会成员买午餐,为什么不在零值参数上领先 0x?
【问题讨论】:
胡乱猜测:0 是 0 与基数无关,因此无需指定。 值得注意的是,您可以通过编写"0x%08x"
来获得 always 的行为,包括前导 0x
,而标准描述的行为将更难以获得一个总是包含前导0x
的库。也许标准委员会正在针对更难获得的情况进行优化,而不是针对绝对最常见的情况? (当然,您不能将"%#10x"
更改为"0x%8x"
,但是很难想象有人希望看到没有零填充的0x0
。)
C89 Rationale (html) 或 C99 Rationale (PDF) 中没有提及这一点。
【参考方案1】:
标准好像是这样写的:
%#x
和 %#o
尝试保证使用 strtol
和 base = 0
可以正确解析输出。
在这些情况下,#
标志会添加尽可能少的额外字符。例如,0 打印为0
,因为不需要添加额外的0x
。如果您不指定最小字段宽度和 0-padding,这很有意义。
如果您想始终添加0x
,您通常可以简单地编写类似0x%x
的内容。因此,%#x
似乎仅在您真正想要对 0 进行特殊处理的特殊情况下有用。但 0x
的前置处理不会' t 适用于默认字段宽度说明符,例如)0x%12x
由 0x 和十六进制数字之间的空格右对齐,在这种情况下这不太可能是想要的。对于这种情况,需要使用 sprintf 进行额外的准备传递,因此像 "0x2ac2"
这样的十六进制字符串可以用 printf( "%12s", hexstr);
之类的东西右对齐 幸运的是,用 0
对齐而不是使用像 printf( "0x%012x", hexstr);
之类的空格来对齐预期为解析器生成有效的十六进制数字。
现在%#x
被指定为单独工作的方式很有意义。像%010x
这样的东西被指定为单独工作的方式很有意义。您正在组合这两个修饰符,最终结果可以说是奇怪的。对于另一个应用程序,例如自动生成整洁的 C 代码来初始化表,使用 0,
而不是 0x0
不是问题。
但没有必要将%#x
和%010x
结合起来。你可以写0x%08x
来做你想做的事。
【讨论】:
发布答案后,我注意到@ruakh 已经在评论中给出了基本相同的信息。道歉。 +1。没有必要道歉。答案比 cmets 好。我将我的想法作为评论而不是答案发布,因为我知道它们不可能是完整的;但你的回答更彻底,也很有意义。 感谢回答和 cmets!与 strtol 兼容的想法是有道理的。现在是时候将大量代码更改为 0x%08x。 为什么1
也没有这种行为?它与0
一样明确。无需添加额外的0x
。以上是关于为啥使用 C printf 格式“%#x”打印 0(零)而没有前导“0x”?的主要内容,如果未能解决你的问题,请参考以下文章
STM32为啥要用重定向printf来打印串口数据?直接用串口发送函数不行吗
请教c语言中打印变量的大小被警告是为啥(VS2019/Debug/x64)?