为啥使用 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 尝试保证使用 strtolbase = 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来打印串口数据?直接用串口发送函数不行吗

为啥 5/7 打印 0?

请教c语言中打印变量的大小被警告是为啥(VS2019/Debug/x64)?

C语言printf函数输出格式%x和%p的差别

C语言,为啥用 printf("%d",c*0.85)出来的结果不对?

c语言打印double类型