为什么使用printf在屏幕上打印十六进制char表示有时会打印一个4字节的数字?
这是我写的代码
#include <stdio.h>
#include <stdint.h>
#include<stdio.h>
int main(void) {
char testStream[8] = {'a', 'b', 'c', 'd', 0x3f, 0x9d, 0xf3, 0xb6};
int i;
for(i=0;i<8;i++){
printf("%c = 0x%X, ", testStream[i], testStream[i]);
}
return 0;
}
以下是输出:
a = 0x61, b = 0x62, c = 0x63, d = 0x64, ? = 0x3F, � = 0xFFFFFF9D, � = 0xFFFFFFF3, � = 0xFFFFFFB6
5 回答
char
似乎已在您的系统上签名 . 使用整数的标准"two's complement"表示,具有最高有效位设置意味着它是负数 .为了将
char
传递给像printf
这样的vararg函数,它必须扩展为int
. 要保留其值,符号位将复制到所有新位(0x9D
→0xFFFFFF9D
) . 现在%X
转换期望并打印unsigned int
,您可以看到负数中的所有设置位而不是减号 .如果您不想这样,则必须使用
unsigned char
或将其传递给unsigned char
,并将其传递给printf
. 与signed char
相比,unsigned char
没有额外的位,因此具有相同的位模式 . 当无符号值被扩展时,新位将为零,并且您首先得到预期的值 .从C标准(C11 6.3.2.1/8)
%X
的描述:您没有提供
unsigned int
作为参数1,因此您的代码会导致未定义的行为 .在这种情况下,未定义的行为表现为
printf
的实现,为%X
编写代码,就像你只传递unsigned int
一样 . 您所看到的是unsigned int
值,其具有与您作为参数给出的负整数值相同的位模式 .还有另一个问题,有:
在您的系统上,
char
的范围是-128
到+127
. 但是0x9d
,即157
,超出了char
的范围 . 这会导致实现定义的行为(并可能引发信号);这里最常见的实现定义是将选择与(unsigned char)0x9d
具有相同位模式的char
.1虽然它表示
unsigned int
,但此部分通常被解释为表示允许带符号的int
或任何较低等级的参数,并且具有非负值 .在您的计算机上,默认情况下会签署
char
. 将类型更改为unsigned char
,您将获得您期望的结果 .A Quick explanation on why this is
在计算机系统中,MSB(最高有效位)是具有最高值的位(最左位) . 数字的MSB用于确定数字是正数还是负数 . 即使
char
类型长度为8位,signed char
也只能使用7位,因为第8位确定其是正还是负 . 这是一个例子:因为
signed char
使用第8位作为有符号标志,所以它实际用于存储数字的位数是7位 . 您可以以7位存储的最大值是127(7F
,十六进制) .为了将数字从正数转换为负数,计算机使用称为二重符号的东西 . 工作原理是所有位都被反转,然后
1
被添加到值中 . 这是一个例子:当你声明
char testStream[8]
时,编译器假设你想要signed char
. 当您分配了0x9D
或0xF3
的值时,这些数字大于0x7F
,这是可以容纳7位有符号字符的最大数字 . 因此,当您尝试printf
屏幕的值时,它会扩展为int
并填充FF
.我希望这个解释能够解决问题!
char
在您的平台上签名:第6个字符的初始化程序0x9d
大于CHAR_MAX
(157> 127),它被转换为char
作为负值-99
(157 - 256 = -99)存储在textStream
中的偏移5
处 .将
textStream[5]
作为参数传递给printf
时,它首先被提升为int
,值为-99
.printf
实际上希望"%X"
为"%X"
格式说明符 .在您的体系结构上,
int
是32位,2的补码表示负值,因此-99
作为int
传递的值被解释为4294967197
(2 ^ 32-99),其十六进制表示为0xFFFFFF9D
. 在不同的架构上,它可能是别的东西:在16位DOS上,你会得到0xFF9D
,在64位Cray上你可能得到0xFFFFFFFFFFFFFF9D
.为避免这种混淆,您应该将
printf
的操作数转换为(unsigned char)
. 尝试用此替换你的printf
:这里似乎发生的是隐式char - > int - > uint cast . 当正char被转换为int时,没有任何不好的事情发生 . 但是如果负的字符如0x9d,0xf3,0xb6转换为int将使它们保持负值,因此它们变为0xffffff9d,0xfffffff3,0xffffffb6 . 不是实际值没有改变,即0xffffff9d == -99和0x9d == -99 . 要正确打印它们,您可以将代码更改为