unsigned char的格式说明符

时间:2014-12-18 13:10:05

标签: c

说我要打印unsigned char

unsigned char x = 12;

这是正确的。这样:

printf("%d",x);

或者这个:

printf("%u",x);

事情就在其他地方我遇到过这样的讨论:

- 即使ch更改为unsigned char,代码的行为也不是由C标准定义的。这是因为unsigned char被提升为int(在普通的C实现中),因此将int传递给printf以获取指定符%u。但是,%u需要unsigned int,因此类型不匹配,C标准不定义行为

- 您的评论不正确。 C11标准规定转换说明符必须与函数参数本身的类型相同,而不是提升类型。这一点在hh长度修饰符的描述中也有具体说明:"参数将根据整数提升进行提升,但在打印之前,其值应转换为有符号字符或无符号字符。

哪个是正确的?任何可靠的消息来源都说这个问题? (从这个意义上讲,我们还应该用%d打印unsigned short int,因为它可以提升为int?)。

4 个答案:

答案 0 :(得分:8)

正确的是*:

printf("%d",x);

这是因为默认参数促销,因为printf()是可变参数函数。这意味着unsigned char值始终会提升为int

从N1570(C11草案)6.5.2.2/6 函数调用(强调我的未来):

  

如果表示被调用函数的表达式具有类型   不包含原型,执行整数促销   每个参数和类型float的参数都被提升为   double。这些被称为默认参数促销

6.5.2.2/7子条款告诉:

  

函数原型声明符中的省略号表示法导致   参数类型转换在最后声明的参数后停止。   默认参数促销在尾随参数上执行

这些整数促销在6.3.1.1/2 布尔,字符和整数中定义:

  

如果int 可以代表原始类型的所有值(受限制   通过宽度,对于位字段),该值被转换为int;   否则,它将转换为unsigned int。这些被称为   整数提升 .58)所有其他类型均未被整数更改   促销。

此引文回答了您unsigned short的第二个问题(请参阅下面的评论)。


*超过8位unsigned char除外(例如它可能占用16位),请参阅@ chux的answer

答案 1 :(得分:7)

unsigned char x = 12的正确格式说明符取决于许多事项:

如果INT_MAX >= UCHAR_MAX(通常是这种情况),请使用"%d"。在这种情况下,unsigned char会提升为int

printf("%d",x);

否则请使用"%u"(或"%x""%o")。在这种情况下,unsigned char会提升为unsigned

printf("%u",x);

最新的编译器支持"hh"长度修饰符,可以补偿这种歧义。由于可变参数的标准促销,xint升级为unsignedprintf()unsigned char会在打印前将其转换为printf("%hhu",x);

"hh"

如果处理没有printf("%u", (unsigned) x); 的旧编译器或寻求高度可移植的代码,请使用显式转换

unsigned short

相同的问题/答案适用于INT_MAX >= USHRT_MAX,期待"h"并使用"hh"代替{{1}}。

答案 2 :(得分:2)

unsigned charunsigned short都可以随时使用%u安全打印。默认参数提升会将其转换为intunsigned int。如果它们被提升为后者,一切都很好(格式说明符和传递的类型匹配),否则C11(n1570)6.5.2.2 p6,第一个子弹,适用:

  
      
  • 一个提升类型是有符号整数类型,另一个提升类型是相应的无符号整数类型,并且该值可在两种类型中表示;
  •   

标准非常明确,默认参数促销适用于printf的可变参数,例如对于(大多数无用的)hhh长度修饰符(同上.7.21.6.1 p7,emph.mine)再次提及:

  

hh - 指定以下diouxX转换说明符适用于signed charunsigned char参数(参数将根据整数提升进行提升,但其值应转换为signed char或打印前unsigned char); [...]

答案 3 :(得分:1)

对于跨平台开发,我通常使用inttypes.h

绕过促销问题

http://pubs.opengroup.org/onlinepubs/009695399/basedefs/inttypes.h.html

此标头(符合C99标准)定义了基本类型的所有printf类型。所以如果你想要一个uint8_t(我强烈建议使用的语法而不是unsigned char)我会使用

#include <inttypes.h>
#include <stdint.h>
uint8_t x;
printf("%" PRIu8 "\n",x);