C语言中printf输出ffffffb1而非b1的原因咨询
问题解析:有符号char的符号扩展导致输出异常
这是个非常典型的有符号字符的符号扩展问题,咱们一步步把它拆解清楚:
先确认已知前提
你的Intel i7处理器是小端字节序,所以unsigned int x = 0x15b11056在内存里的存储顺序(从低地址到高地址)是:
- 第1个地址:
0x56 - 第2个地址:
0x10 - 第3个地址:
0xb1 - 第4个地址:
0x15
这和你观察到的输出规律完全一致,小端序的部分没有问题。
核心原因:默认char是有符号类型
在绝大多数C编译器(包括你用的在线IDE的编译器)中,char类型默认是signed char(有符号字符)。当你用*(c+2)取出第3个地址的0xb1时:
0xb1的二进制是10110001,最高位是1,对于signed char来说,这代表一个负数(对应十进制-79,遵循补码规则)。- 当你把这个signed char值传给
printf的%x格式符时,会触发整数提升:signed char会被提升为int类型。为了保持负数的数值不变,提升时会把高位全部补1,于是8位的0xb1就变成了32位int的0xffffffb1,这就是你看到的异常输出。
而之前用0x15711056时,第3个地址的0x71二进制是01110001,最高位是0,作为signed char是正数,提升为int时高位补0,所以输出还是0x71,符合你的预期。
解决方法
有两种简单的方式可以解决这个问题:
- 方式1:将字符指针声明为无符号类型
修改指针定义为:
这样取出的字节会被当作无符号值,提升为int时高位补0,unsigned char *c = (unsigned char*) &x;0xb1就会正常输出为0xb1。 - 方式2:打印时强制转换为无符号字符
不需要修改指针,在打印时做类型转换:printf("Value at third address %x\n", (unsigned char)*(c+2));
额外验证
你可以自己测试一下:如果把x改成0x15811056,第3个地址的0x81也会触发同样的符号扩展,输出0xffffff81,这就能验证咱们的结论啦。
内容的提问来源于stack exchange,提问作者Prashant Pathak
相关产品推荐
相关产品推荐

