238

Why, when printing a number in hexadecimal as an 8 digit number with leading zeros, does %#08X not display the same result as 0x%08X?

When I try to use the former, the 08 formatting flag is removed, and it doesn't work with just 8.

4

5 回答 5

345

#部分0x在输出字符串中为您提供了一个。0x计数部分中列出的“8”个字符08。如果您希望它是相同的,您需要要求 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
于 2013-02-06T16:24:43.640 回答
62

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

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

于 2013-02-06T16:25:22.863 回答
41

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

尝试以下代码的变体:

#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功能fprintf

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

(强调补充。)


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

对于打印地址,请使用<inttypes.h>标题、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 位代码)。

于 2013-02-06T16:25:35.813 回答
9

#除非值为,否则会导致0x(或0Xfor )在输出之前添加,因此如果您希望始终出现在输出中,则不应使用。%#X0#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".

于 2021-04-27T12:26:26.997 回答
-1

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

int main (void)
{
    uint8_t a;
    uint32_t b;
    a = 15;
    b = a << 28;
    printf("%p", b);
    return 0;
}

输出:

0xf0000000
于 2021-02-23T09:52:41.947 回答