我正在尝试读取一行字符,然后打印出十六进制字符的等效字符。
例如,如果我的字符串为"0xc0 0xc0 abc123"
,其中前两个字符为十六进制c0
,其余字符为ASCII abc123
,那么我应该< / p>
c0 c0 61 62 63 31 32 33
然而,使用printf
的{{1}}给了我
%x
如何在没有ffffffc0 ffffffc0 61 62 63 31 32 33
的情况下获得我想要的输出?为什么只有c0(和80)有"ffffff"
,而不是其他字符?
答案 0 :(得分:109)
您看到了ffffff
,因为char
已在您的系统上签名。在C中,诸如printf
之类的vararg函数会将小于int
的所有整数提升为int
。由于char
是一个整数(在您的情况下为8位有符号整数),因此您的字符将通过符号扩展名提升为int
。
由于c0
和80
具有前导1位(并且作为8位整数为负),因此它们将被符号扩展,而样本中的其他符号则不会。< / p>
char int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061
这是一个解决方案:
char ch = 0xC0;
printf("%x", ch & 0xff);
这将屏蔽高位并仅保留您想要的低8位。
答案 1 :(得分:54)
确实,有类型转换为int。 您也可以使用%hhx说明符强制类型为char。
printf("%hhX", a);
在大多数情况下,您还需要设置最小长度以用零填充第二个字符:
printf("%02hhX", a);
ISO / IEC 9899:201x说:
7长度修饰符及其含义为: hh指定以下d,i,o,u,x或X转换说明符适用于a signed char或unsigned char参数(参数将具有 按整数促销推广,但其价值应为 在打印之前转换为signed char或unsigned char);或者那个 以下
答案 2 :(得分:26)
您可以创建一个unsigned char:
unsigned char c = 0xc5;
打印它将提供C5
而不是ffffffc5
。
只有大于127的字符用ffffff
打印,因为它们是否定的(字符已签名)。
或者您可以在打印时投射char
:
char c = 0xc5;
printf("%x", (unsigned char)c);
答案 3 :(得分:11)
您可能将值0xc0存储在char
变量中,可能是签名类型,并且您的值为负(最高位设置)。然后,在打印时,它被转换为int
,并且为了保持语义等价,编译器用0xff填充额外的字节,因此负int
将具有与您的负char
相同的数值。 1}}。要解决此问题,请在打印时转换为unsigned char
:
printf("%x", (unsigned char)variable);
答案 4 :(得分:11)
您可以使用hh
告诉printf
该参数是无符号字符。使用0
获取零填充,使用2
将宽度设置为2. x
或X
,用于低/大写十六进制字符。
uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"
编辑:如果读者担心2501的断言,这是不正确的&#39;正确的&#39;格式说明符我建议他们再次阅读printf
link。具体做法是:
即使%c需要int参数,由于调用可变参数函数时发生的整数提升,传递char也是安全的。
固定宽度字符类型(int8_t等)的正确转换规范在标题
<cinttypes>
(C ++)或<inttypes.h>
(C)中定义(尽管PRIdMAX,PRIuMAX, etc与%jd,%ju等同义)。
至于他关于signed vs unsigned的观点,在这种情况下它并不重要,因为值必须始终为正且容易适合有符号的int。无论如何,没有签名的hexyximal格式说明符。
编辑2 :(&#34;何时承认 - 重新错误&#34;版本):
如果您阅读了第311页的the actual C11 standard(PDF格式的329),您会发现:
hh:指定以下
d
,i
,o
,u
,x
或X
转换说明符适用于signed char
或unsigned char
参数(参数将根据整数提升进行提升,但在打印前其值应转换为signed char
或unsigned char
);或者以下n
转换说明符适用于指向signed char
参数的指针。
答案 5 :(得分:2)
您可能正在从已签名的char数组中打印。从unsigned char数组打印或用0xff掩盖值:例如ar [i]&amp; 0xFF的。由于高(符号)位已设置,因此c0值正在进行符号扩展。
答案 6 :(得分:-1)
尝试这样的事情:
int main()
{
printf("%x %x %x %x %x %x %x %x\n",
0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33);
}
产生这个:
$ ./foo
c0 c0 61 62 63 31 32 33