为什么printf显示十六进制数的错误值

时间:2017-08-19 20:39:48

标签: c hex printf

代码

char a; 
a = 0xf1;
printf("%x\n", a);

输出

fffffff1

printf()显示4个字节,我们在a中确实有一个字节。

这种不当行为的原因是什么?

我该如何纠正?

3 个答案:

答案 0 :(得分:4)

printf是一个变量参数函数,因此编译器尽力而为,但不能检查格式说明符和参数类型之间的严格一致性。

您在这里传递char %x(整数,十六进制)格式说明符。

因此,该值会提升为有符号整数(因为> 127:负值字符和char在大多数系统上都已签名,在您的系统上是肯定的)

或者:

  • a更改为int(最简单)
  • a更改为unsigned char(由BLUEPIXY建议),负责促销中的签名
  • 将格式更改为%hhx,如各种文档中所述(请注意,我的gcc 6.2.1编译器hhx无法识别,即使hx是)

请注意,编译器会在到达printf之前警告您您遇到问题:

gcc -Wall -Wpedantic test.c
test.c: In function 'main':
test.c:6:5: warning: overflow in implicit constant conversion [-Woverflow]
 a = 0xf1;

答案 1 :(得分:4)

  

这种不当行为的原因是什么?

这个问题看起来strangely similar给另一个我已回答的问题;它甚至使用相同的值(0xf1)。在该答案中,我提供了一些信息,以便了解将小值(例如char)传递给变量函数(例如printf)时发生的转换。这里重复这些信息毫无意义。

此问题确实不同,因为在该问题中原始值实际上不是0xf1;它不能是因为char类型在该系统上签名。如果您从CHAR_MIN检查CHAR_MAX<limits.h>,您也可能会发现您的char类型已签名,因此0xf1不适合char内的整数值。

相反,它最终会以实现定义的方式进行转换,对于我们大多数人来说,这意味着最终可能会有一个高位成为符号位。当这些值提升为int时(为了传递给printf),会发生符号扩展以保留该值(即,值为-1的char应为转换为值为-1的int作为int,因此您的示例的基础表示可能会从0xf1转换为0xfffffff1

printf("CHAR_MIN .. CHAR_MAX: %d .. %d\n", CHAR_MIN, CHAR_MAX);
printf("Does %d fit? %s\n", '\xFF', '\xFF' >= CHAR_MIN && '\xFF' <= CHAR_MAX ? "Yes!"
                                                                             : "No!");

printf("%d %X\n", (char) -1, (char) -1); // Both of these get converted to int
printf("%d %X\n", -1, -1);               // ... and so are equivalent to these
  

我该如何纠正?

使用适合值a的类型声明0xf1,例如intunsigned char

答案 2 :(得分:0)

您应该使用int a而不是char a,因为char是无符号的,并且只能存储0到255之间的1个字节。 并且十六进制数需要许多存储来存储它,并且int存储大小也是2或4个字节。因此,最好使用int来存储十六进制数。