Printing hexadecimal characters in C

我试图读入一行字符,然后打印出相当于十六进制的字符。

For example, if I have a string that is "0xc0 0xc0 abc123", where the first 2 characters are c0 in hex and the remaining characters are abc123 in ASCII, then I should get

c0 c0 61 62 63 31 32 33

然而,使用 %xprintf给我

ffffffc0 ffffffc0 61 62 63 31 32 33

没有 "ffffff",我如何得到我想要的输出?为什么只有 c0(和80)有 ffffff,而其他字符没有?

446356 次浏览

您看到的是 ffffff,因为 char已经在您的系统上签名了。在 C 语言中,诸如 printf之类的 vararg 函数将把所有小于 int的整数提升到 int。因为 char是一个整数(在您的例子中是8位有符号整数) ,所以您的字符通过符号扩展被提升到 int

由于 c080有一个前导1位(作为一个8位整数是负数) ,所以它们是符号扩展的,而示例中的其他值不是。

char    int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061

这里有一个解决办法:

char ch = 0xC0;
printf("%x", ch & 0xff);

这将屏蔽掉上面的位,只保留你想要的下面的8位。

您可能正在从已签名的字符数组打印。从无符号字符数组打印或用0xff 掩盖该值: 例如 ar [ i ] & 0xFF。由于设置了高(符号)位,c0值被符号扩展。

试试这样:

int main()
{
printf("%x %x %x %x %x %x %x %x\n",
0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33);
}

Which produces this:

$ ./foo
c0 c0 61 62 63 31 32 33

您可能将值0xc0存储在一个 char变量中,这可能是一个带符号的类型,并且您的值为负(最重要的位设置)。然后,在打印时,它被转换为 int,为了保持语义等价,编译器用0xff 填充额外的字节,因此负 int将与负 char具有相同的数值。要解决这个问题,只需在打印时转到 unsigned char:

printf("%x", (unsigned char)variable);

实际上,类型转换为 int。 还可以使用% hhx 说明符强制键入 char。

printf("%hhX", a);

在大多数情况下,您还需要设置最小长度,以便将第二个字符填充为零:

printf("%02hhX", a);

ISO/IEC 9899:201x says:

7长度修饰符及其含义如下: Hh 指定以下 d、 i、 o、 u、 x 或 X 转换说明符应用于 有符号的 char 或无符号的 char 参数(参数将具有 根据整数促销提升,但其值应为 在打印前转换为有符号字符或无符号字符) ; 或 追随者

You can create an unsigned char:

unsigned char c = 0xc5;

打印它会得到 C5而不是 ffffffc5

只有大于127的字符才用 ffffff打印,因为它们是负数(字符是有符号的)。

或者你可以在打印的时候抛出 char:

char c = 0xc5;
printf("%x", (unsigned char)c);

You can use hh to tell printf that the argument is an unsigned char. Use 0 to get zero padding and 2 to set the width to 2. x or X for lower/uppercase hex characters.

uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"

编辑 : 如果读者担心2501断言这不是“正确”的格式说明符,我建议他们再读一遍 printf链路。具体来说:

尽管% c 期望使用 int 参数,但是传递 char 是安全的,因为在调用可变参数函数时会发生整数升级。

固定宽度字符类型(int8 _ t 等)的正确转换规范在头 <cinttypes>(C + +)或 <inttypes.h>(C) (虽然 PRIdMAX、 PRIuMAX 等等是% jd、% ju 等的同义词)中定义。

至于他关于有符号 vs 无符号的观点,在这种情况下没有关系,因为值必须总是正的,并且很容易适合有符号的整型。反正也没有有符号的六进制格式说明符。

编辑2 : (“什么时候承认你错了”版本) :

如果你阅读第311页的 实际的 C11标准(PDF 格式的329页) ,你会发现:

hh: Specifies that a following d, i, o, u, x, or X conversion specifier applies to a signed char or unsigned char argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to signed char or unsigned char before printing); or that a following i0 conversion specifier applies to a pointer to a signed char argument.