为什么使用printf在屏幕上打印字符的十六进制表示有时会打印一个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
答案 0 :(得分:5)
char
似乎已在您的系统上签名。使用标准的#2;补充&#34;整数的表示,具有最高有效位设置意味着它是负数。
为了将char
传递给像printf
这样的vararg函数,必须将其扩展为int
。为了保留其值,将符号位复制到所有新位(0x9D
→0xFFFFFF9D
)。现在%X
转换期望并打印unsigned int
,您可以看到负数中的所有设置位而不是减号。
如果您不想这样做,则必须使用unsigned char
或在将unsigned char
传递给printf
时将其投放到unsigned char
。与signed char
相比,jest-cli
没有额外的位,因此具有相同的位模式。当无符号值被扩展时,新位将为零,并且您首先得到预期的值。
答案 1 :(得分:1)
在您的计算机上,默认情况下会对char
进行签名。将类型更改为unsigned char
,您就会得到您期望的结果。
快速解释原因
在计算机系统中,MSB(最高有效位)是具有最高值的位(最左位)。数字的MSB用于确定数字是正数还是负数。即使char
类型长度为8位,signed char
也只能使用7位,因为第8位确定其是正还是负。这是一个例子:
Data Type: signed char
Decimal: 25
Binary: 00011001
^
|
--- Signed flag. 0 indicates positive number. 1 indicates negtive number
因为signed char
使用第8位作为有符号标志,所以它实际用于存储数字的位数是7位。您可以以7位存储的最大值为127(十六进制为7F
)。
为了将数字从正数转换为负数,计算机使用称为“两个赞美”的东西。工作原理是所有位都被反转,然后将1
添加到值中。这是一个例子:
Decimal: 25
Binary: 00011001
Decimal: -25
Binary: 11100111
当您声明char testStream[8]
时,编译器假定您需要signed char
。当您分配了0x9D
或0xF3
的值时,这些数字会大于0x7F
,这是可以容纳7位有符号字符的最大数字。因此,当您尝试printf
屏幕的值时,它会展开为int
并填充FF
。
我希望这个解释可以解决问题!
答案 2 :(得分:1)
char
已在您的平台上签名:第6个字符的初始值设定项0x9d
大于CHAR_MAX
(157> 127),转换为char
为负值-99
(157 - 256 = -99)存储在5
的偏移textStream
处。
当您将textStream[5]
作为参数传递给printf
时,它首先会提升为int
,其值为-99
。 printf
实际上需要unsigned int
格式说明符{。}}。
在您的体系结构中,"%X"
是32位,带有2的补码表示负值,因此int
传递的值-99
被解释为int
(2 ^ 32-99),其十六进制表示为4294967197
。在不同的架构上,它可能是其他东西:在16位DOS上,你会得到0xFFFFFF9D
,在64位Cray上你可能得到0xFF9D
。
为避免这种混淆,您应该将0xFFFFFFFFFFFFFF9D
的操作数强制转换为printf
。请尝试将此(unsigned char)
替换为:
printf
答案 3 :(得分:1)
根据C标准(C11 6.3.2.1/8)对%X
:
unsigned int 参数转换为无符号八进制(o),无符号 样式dddd中的十进制(u)或无符号十六进制表示法(x或X);该 字母abcdef用于x转换,字母ABCDEF用于X. 转换。
您没有提供unsigned int
作为参数 1 ,因此您的代码会导致未定义的行为。
在这种情况下,未定义的行为表现为printf
为%X
编写代码的实现,就好像您只传递unsigned int
一样。你看到的是unsigned int
值,它与你给出的负整数值具有相同的位模式。
还有另一个问题,包括:
char testStream[8] = {'a', 'b', 'c', 'd', 0x3f, 0x9d, 0xf3, 0xb6};
在您的系统上,char
的范围是-128
到+127
。但是0x9d
157
超出了char
的范围。这会导致实现定义的行为(并可能引发信号);这里最常见的实现定义是选择与char
具有相同位模式的(unsigned char)0x9d
。
1 虽然它显示unsigned int
,但此部分通常被解释为表示带有非负值的带符号int
或任何较低等级的参数,也允许。
答案 4 :(得分:0)
这里似乎发生的是隐式char - &gt; int - &gt; uint cast。当正char被转换为int时,没有任何不好的事情发生。但是如果为负的字符如0x9d,0xf3,0xb6转换为int将使它们保持负值,因此它们变为0xffffff9d,0xfffffff3,0xffffffb6。不是实际值没有改变,即0xffffff9d == -99和0x9d == -99。 要正确打印它们,您可以将代码更改为
printf("%c = 0x%X, ", testStream[i] & 0xff, testStream[i] & 0xff);