为什么 printf 显示十六进制数字的错误值[重复]

问题描述 投票:0回答:3

代码

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

输出

fffffff1

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

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

我该如何纠正?

c hex printf
3个回答
4
投票

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

这个问题看起来与我回答过的另一个问题“奇怪地相似”;它甚至包含类似的值(0xfffffff1)。在该答案中,我提供了一些所需的信息,以了解当您将小值(例如

char
)传递给可变参数函数(例如
printf
)时会发生什么转换。没有必要在这里重复这些信息。
如果您检查 

CHAR_MIN

中的

CHAR_MAX
<limits.h>
,您可能会发现您的
char
类型是带符号的,因此
0xf1
不适合作为
char
内部的整数值。
相反,它最终以实现定义的方式进行转换,这对于我们大多数人来说意味着最终可能会导致高位之一成为符号位。当这些值提升为 

int

(为了传递到

printf
)时,会发生符号扩展以保留该值(即,值为 -1 的
char
应转换为具有以下值的 int):值 -1 作为
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
,例如
int
unsigned char
    


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;



0
投票
int a

而不是

char a
,因为
char
是无符号的,只能存储从 0 到 255 的 1 个字节。 而十六进制数需要很多存储空间来存储,而且
int
存储大小为2或4字节。所以这里最好使用
int
来存储十六进制数。
    

© www.soinside.com 2019 - 2024. All rights reserved.