在C中打印十六进制字符

Ray*_*yne 88 c printf hex

我正在尝试读取一行字符,然后打印出字符的十六进制等效值.

例如,如果我有一个字符串,"0xc0 0xc0 abc123"前两个字符是c0十六进制,其余字符是abc123ASCII,那么我应该得到

c0 c0 61 62 63 31 32 33
Run Code Online (Sandbox Code Playgroud)

但是,printf使用%x给了我

ffffffc0 ffffffc0 61 62 63 31 32 33
Run Code Online (Sandbox Code Playgroud)

如何在不使用的情况下获得我想要的输出"ffffff"?为什么只有c0(和80)有ffffff,但没有其他字符?

Mys*_*ial 115

您看到ffffff因为char您的系统已签名.在C语言中,可变参数的功能,比如printf将促进所有整数小于intint.由于char是一个整数(在您的情况下为8位有符号整数),因此您的字符将int通过符号扩展名提升.

由于c0并且80具有前导1位(并且是8位整数的负数),所以它们是符号扩展的,而样本中的其他符号则不是.

char    int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061
Run Code Online (Sandbox Code Playgroud)

这是一个解决方案:

char ch = 0xC0;
printf("%x", ch & 0xff);
Run Code Online (Sandbox Code Playgroud)

这将屏蔽高位并仅保留您想要的低8位.

  • 我使用强制转换为`unsigned char`的解决方案是gcc4.6中针对x86-64的一个较小的指令... (15认同)
  • 也许我可以帮忙。这是(技术上)未定义的行为,因为说明符“x”需要无符号类型,但 ch 被提升为 int。正确的代码只需将 ch 强制转换为 unsigned,或者使用强制转换为 unsigned char 和说明符:“hhx”。 (2认同)

小智 57

实际上,有类型转换为int.您还可以使用%hhx说明符强制类型为char.

printf("%hhX", a);
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,您还需要设置最小长度以使用零填充第二个字符:

printf("%02hhX", a);
Run Code Online (Sandbox Code Playgroud)

ISO/IEC 9899:201x说:

7长度修饰符及其含义为:hh指定以下d,i,o,u,x或X转换说明符适用于signed char或unsigned char参数(该参数将根据整数提升进行提升,但在打印前,其值应转换为有符号字符或未签名字符); 或者说是以下


Hic*_*ham 27

您可以创建一个unsigned char:

unsigned char c = 0xc5;
Run Code Online (Sandbox Code Playgroud)

打印它会给予C5而不是ffffffc5.

只打印大于127的字符,ffffff因为它们是负数(字符是有符号的).

或者你可以施放char同时打印:

char c = 0xc5; 
printf("%x", (unsigned char)c);
Run Code Online (Sandbox Code Playgroud)

  • +1真正的最佳答案,显式键入尽可能接近数据声明(但不要更接近). (3认同)

Tim*_*mmm 12

您可以hh用来告诉printf参数是unsigned char.使用0以获得零填充和2所述宽度设置为2 xX更低/大写十六进制字符.

uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"
Run Code Online (Sandbox Code Playgroud)

编辑:如果读者担心2501断言这不是'正确的'格式说明符,我建议他们再次阅读printf链接.特别:

即使%c需要int参数,由于调用可变参数函数时发生的整数提升,传递char也是安全的.

固定宽度字符类型(int8_t等)的正确转换规范在标题<cinttypes>(C++)或<inttypes.h>(C)中定义(尽管PRIdMAX,PRIuMAX等与%jd,%ju等同义).

至于他关于signed vs unsigned的观点,在这种情况下它并不重要,因为值必须始终是正数并且很容易适合有符号的int.无论如何,没有签名的hexyximal格式说明符.

编辑2 :("何时承认 - 你错了"版本):

如果您在第311页(PDF的第329页)上阅读了实际的C11标准,您会发现:

HH:指定一以下d,i,o,u,x,或X转换说明适用于一个signed charunsigned char参数(该参数将被提升根据整数促销,但它的值应被转换成signed charunsigned char之前印刷); 或者以下n转换说明符适用于指向signed char参数的指针.


lve*_*lla 11

您可能将值0xc0存储在char变量中,可能是有符号类型,并且您的值为负(最高位设置).然后,当打印时,它被转换为int,并且为了保持语义等价,编译器用0xff填充额外的字节,因此负数int将具有与负数相同的数值char.要解决此问题,请unsigned char在打印时强制转换为:

printf("%x", (unsigned char)variable);
Run Code Online (Sandbox Code Playgroud)