在C中打印hex字符
我试图读取一行字符,然后打印出相当于字符的hex。
例如,如果我有一个string是"0xc0 0xc0 abc123"
,其中前两个字符是hex的c0
,其余的字符是abc123
的ASCII,那么我应该得到
c0 c0 61 62 63 31 32 33
但是,使用%x
printf
给了我
ffffffc0 ffffffc0 61 62 63 31 32 33
如何在没有"ffffff"
情况下获得我想要的输出? 为什么只有c0(和80)有ffffff
,而不是其他的字符?
你正在看到ffffff
因为char
在你的系统上被签名。 在C中,可变参数如printf
会将所有小于int
整数提升为int
。 由于char
是一个整数(在你的情况8位有符号整数),你的字符正在通过符号扩展升级到int
。
由于c0
和80
有一个前导1位(并且是8位整数的负数),所以它们正在被符号扩展,而其他样例中的其他则不是。
char int c0 -> ffffffc0 80 -> ffffff80 61 -> 00000061
这是一个解决scheme:
char ch = 0xC0; printf("%x", ch & 0xff);
这将掩盖高位,只保留你想要的低8位。
的确,有types转换为int。 你也可以使用%hhx说明符强制types为char。
printf("%hhX", a);
你可以创build一个无符号的char:
unsigned char c = 0xc5;
打印它会给C5
而不是ffffffc5
。
只有大于127的字符才会用ffffff
打印,因为它们是负数(char有符号)。
或者您可以在打印时投下char
:
char c = 0xc5; printf("%x", (unsigned char)c);
您可能将值0xc0存储在char
variables中,可能是签名types,而您的值是负值(设置最重要的位)。 然后,打印时,它被转换为int
,并保持语义等价,编译器用0xff填充额外的字节,所以负的int
将具有相同的负数char
数值。 要解决这个问题,打印时只需转换为unsigned char
:
printf("%x", (unsigned char)variable);
你可以使用hh
来告诉printf
参数是一个无符号的字符。 使用0
获得零填充,使用2
将宽度设置为2. x
或X
表示小写/大写hex字符。
uint8_t a = 0x0a; printf("%02hhX", a); // Prints "0A" printf("0x%02hhx", a); // Prints "0x0a"
编辑 :如果读者关心2501的断言,这是不正确的格式说明符,我build议他们再次阅读printf
链接 。 特别:
尽pipe%c需要int参数,但因为在调用可变参数函数时发生整数提升,所以传递char是安全的。
在头文件
<cinttypes>
(C ++)或<inttypes.h>
(C)中定义了固定宽度字符types(int8_t等)的正确转换规范(虽然PRIdMAX,PRIuMAX等与%jd,% ju等) 。
至于他关于有符号还是无符号的观点,在这种情况下,这并不重要,因为这些值必须始终是正数,并且容易符合一个有符号整数。 无论如何,没有签名的hex格式说明符。
编辑2 :(“何时承认你是错误的”版本):
如果您阅读311页上的实际C11标准 (PDF格式的329),则会发现:
hh:指定后面的
d
,i
,o
,u
,x
或X
转换说明符适用于带signed char
或unsigned char
参数(参数将根据整数提升进行提升,但其值将转换为带signed char
打印之前的signed char
或unsigned char
); 或者下面的n
转换说明符适用于指向signed char
参数的指针。
您可能正在从一个签名的字符数组打印。 要么从unsigned char数组打印,要么用0xff掩码值:例如ar [i]&0xFF。 由于高(符号)位被设置,c0值被扩展符号。
尝试这样的事情:
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