printf() 十六进制格式

Posted

技术标签:

【中文标题】printf() 十六进制格式【英文标题】:printf() formatting for hexadecimal 【发布时间】:2013-01-21 22:16:29 【问题描述】:

为什么在将十六进制数字打印为带有前导零的 8 位数字时,%#08X显示与 0x%08X 相同的结果?

当我尝试使用前者时,08 格式化标志被删除,它不适用于 8

【问题讨论】:

你的意思是0x%.8X 吗?那用零填充。 (0x 只是序言,但您可能已经意识到这一点)。 【参考方案1】:

# 部分在输出字符串中为您提供0x0x 计入08 部分中列出的“8”个字符。如果要相同,则需要要求 10 个字符。

int i = 7;

printf("%#010x\n", i);  // gives 0x00000007
printf("0x%08x\n", i);  // gives 0x00000007
printf("%#08x\n", i);   // gives 0x000007

同时更改x 的大小写,会影响输出字符的大小写。

printf("%04x", 4779); // gives 12ab
printf("%04X", 4779); // gives 12AB

【讨论】:

顶行为我输出 14F0x00000007。第二个和第三个工作如书面。 @quantumpotato - 这……很奇怪。第一行和第三行是相同的,除了它们应该产生的 0 的数量。产生这个的编译器/系统/代码行是什么?在打印14F 的那一行之前有任何行吗? 请注意,如果i = 0;,使用%#的版本将不包含0x前缀。 但是十六进制怎么样:0x43A66C31C68491C0 我尝试了以下方法:__int64 int64 = 0x43A66C31C68491C0; printf_s("%#15X %d",int64,int64);但输出是 0XC68491C0,而不是 0x43A66C31C68491C0 关于上面的十六进制 0x43A66C31C68491C0 我已经解决了,解决方法是 0x%I64X ,不是 %#15X【参考方案2】:

“0x”计入八个字符数。你需要"%#010x"

请注意,# 确实将 0x 附加到 0 - 结果将是 0000000000 - 所以你可能实际上应该只使用 "0x%08x"

【讨论】:

感谢您指出# 不会将“0x”添加到“0”!【参考方案3】:

%#08X 转换必须在带有0X 的值之前;这是标准要求的。标准中没有证据表明# 应该改变规范中08 部分的行为,除了0X 前缀被计为长度的一部分(因此您可能想要/需要使用%#010X . 如果像我一样,你喜欢你的十六进制显示为0x1234CDEF,那么你必须使用0x%08X 来获得所需的结果。你可以使用%#.8X,它也应该插入前导零。

尝试以下代码的变体:

#include <stdio.h>

int main(void)

    int j = 0;
    printf("0x%.8X = %#08X = %#.8X = %#010x\n", j, j, j, j);
    for (int i = 0; i < 8; i++)
    
        j = (j << 4) | (i + 6);
        printf("0x%.8X = %#08X = %#.8X = %#010x\n", j, j, j, j);
    
    return(0);

在RHEL 5 机器和Mac OS X v10.7.5 (Lion) 上,输出为:

0x00000000 = 00000000 = 00000000 = 0000000000
0x00000006 = 0X000006 = 0X00000006 = 0x00000006
0x00000067 = 0X000067 = 0X00000067 = 0x00000067
0x00000678 = 0X000678 = 0X00000678 = 0x00000678
0x00006789 = 0X006789 = 0X00006789 = 0x00006789
0x0006789A = 0X06789A = 0X0006789A = 0x0006789a
0x006789AB = 0X6789AB = 0X006789AB = 0x006789ab
0x06789ABC = 0X6789ABC = 0X06789ABC = 0x06789abc
0x6789ABCD = 0X6789ABCD = 0X6789ABCD = 0x6789abcd

我对0的处理有点惊讶;我不清楚为什么省略 0X 前缀,但是有两个独立的系统这样做,它必须是标准的。它证实了我对# 选项的偏见。


零的处理按标准处理。

ISO/IEC 9899:2011 §7.21.6.1 The fprintf function

¶6 标志字符及其含义是: ... # 结果被转换为“替代形式”。 ...对于x(或X) 转换,非零结果以0x(或0X)为前缀。 ...

(已添加重点。)


请注意,使用%#X 将使用大写字母作为十六进制数字,0X 作为前缀;使用%#x 将使用小写字母作为十六进制数字并使用0x 作为前缀。如果您更喜欢0x 作为前缀和大写字母,则必须单独编码0x0x%X。当然,可以根据需要添加其他格式修饰符。

对于打印地址,使用&lt;inttypes.h&gt; 标头和uintptr_t 类型和PRIXPTR 格式宏:

#include <inttypes.h>
#include <stdio.h>

int main(void)

    void *address = &address;  // &address has type void ** but it converts to void *
    printf("Address 0x%.12" PRIXPTR "\n", (uintptr_t)address);
    return 0;

示例输出:

Address 0x7FFEE5B29428

在长度上选择你的毒药——我发现 12 的精度对于运行 macOS 的 Mac 上的地址效果很好。结合. 指定最小精度(数字),它可以可靠地格式化地址。如果您将精度设置为 16,根据我在 Mac 上的经验,额外的 4 位数字始终为 0,但在便携式 64 位代码中使用 16 而不是 12 肯定是有必要的(但您会使用 8 32 位代码)。

【讨论】:

【参考方案4】:

# 导致 0x(或 0X 用于 %#X)被添加到输出之前,除非该值为 0,因此如果您希望始终使用 0x,则不应使用 #出现在输出中。

您可以将宽度字段与0 标志结合使用来生成前导零:%08x 用前导零填充数字到8 的宽度。如果您希望所有 32 位值的输出一致,请使用 "0x08x"

您还可以使用精度字段:%.8x 用前导零填充数字到总共 8 位数。因此,您也可以将"0x%.8x" 用于您的目的。

如果前缀是作为转换的一部分生成的,这些转换规范会有所不同,例如 0x 用于 #- 用于有符号转换中的负数,其长度计入宽度但不计入精度说明符。此外,精度字段可以与宽度字段组合:

printf("|%10x|", 256)      // outputs |       100|
printf("|%010x|", 256)     // outputs |0000000100|
printf("|%#010x|", 256)    // outputs |0x00000100|

printf("|%10.8x|", 256)    // outputs |  00000100|
printf("|%#10.8x|", 256)   // outputs |0x00000100|
printf("|0x%.8x|", 256)    // outputs |0x00000100|

printf("|%10x|", 0)        // outputs |         0|
printf("|%010x|", 0)       // outputs |0000000000|
printf("|%#010x|", 0)      // outputs |0000000000|

printf("|%10.8x|", 0)      // outputs |  00000000|
printf("|%#10.8x|", 0)     // outputs |  00000000|
printf("|0x%.8x|", 0)      // outputs |0x00000000|

我建议使用最后一个:"0x%.8x"

【讨论】:

【参考方案5】:

您始终可以使用“%p”来显示 8 位十六进制数字。

int main (void)

    uint8_t a;
    uint32_t b;
    a = 15;
    b = a << 28;
    printf("%p", b);
    return 0;

输出:

0xf0000000

【讨论】:

什么环境定义了uint8_tuint32_t #include &lt;stdio.h&gt;#include &lt;stdint.h&gt; 开始可能就足够了。 使用该内容,在 Linux 上,gcc -x c Hexprint_p.c 会生成 warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘uint32_t’ aka ‘unsigned int’ [-Wformat=] %p 的输出取决于实现,并且为%p 传递int32_t 具有未定义的行为。绝对不是一个好的解决方案。

以上是关于printf() 十六进制格式的主要内容,如果未能解决你的问题,请参考以下文章

fmt.printf输出的格式

printf格式化输出

Java中printf的使用

(Go)15.golang printf 格式化输出

Linux上printf命令的用法

printf格式化字符输出对应解释