打印存储为字符串的十六进制值会产生意外输出

Printing the hex value stored as a string gives unexpected output

我在字符串中定义了 C 语言的十六进制数字:

char chars[] = "\xfb\x54\x9c\xb2\x10\xef\x89\x51\x2f\x0b\xea\xbb\x1d\xaf\xad\xf8";

然后我想将这些值与另一个值进行比较。它不起作用,如果我打印如下值:

printf("%02x\n", chars[0]);

它写fffffffb。为什么会这样以及如何准确获得 fb 值?

这是因为符号扩展。

改变

printf("%02x\n", chars[0]);

printf("%02x\n", (unsigned char)chars[0]);

%x 格式说明符在 32 位机器上将显示为 4 bytes。由于你已经声明chars为字符数组,当取值fb(负值)时将被符号扩展为fffffffb,其中fb的MSB被设置为它之前的所有其他位。

更多详细信息请参阅此内容sign extension

如果您将 char chars[] 声明为 unsigned char chars[],那么打印结果会如预期的那样。

因为符号扩展。

这将如您所愿地工作:

printf("%02x\n", (unsigned char)chars[0]);

根据关于 %x 格式说明符的标准提及 fprintf()

o,u,x,X

The unsigned int argument is converted to unsigned octal (o), unsigned decimal (u), or unsigned hexadecimal notation (x or X) in the style dddd; [...]

因此,%x 的预期参数类型是 unsigned int

现在,printf() 是一个可变参数函数,只有默认的提升规则适用于它的参数。在您的代码中,charschar 类型的数组(其符号取决于实现),如果

printf("%02x\n", chars[0]);

chars[0] 的值被提升为 int,这不是 %x 的预期类型。因此,输出是错误的,因为 intunsigned int 不是同一类型。 [参考§6.7.2,C11]。所以,没有像

这样的显式转换
printf("%02x\n", (unsigned int)chars[0]);

它调用 undefined behaviour.

FWIW,如果你有一个支持 C99 的编译器,你可以使用 hh 长度修饰符来解决这个问题,比如

 printf("%02hhx\n", (unsigned char)chars[0]);