在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

由于c080有一个前导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存储在charvariables中,可能是签名types,而您的值是负值(设置最重要的位)。 然后,打印时,它被转换为int ,并保持语义等价,编译器用0xff填充额外的字节,所以负的int将具有相同的负数char数值。 要解决这个问题,打印时只需转换为unsigned char

 printf("%x", (unsigned char)variable); 

你可以使用hh来告诉printf参数是一个无符号的字符。 使用0获得零填充,使用2将宽度设置为2. xX表示小写/大写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:指定后面的diouxX转换说明符适用于带signed charunsigned char参数(参数将根据整数提升进行提升,但其值将转换为带signed char打印之前的signed charunsigned 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