unsigned char的格式说明符
说我想打印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 length修饰符的描述中得到了具体解决:“参数将根据整数提升进行提升,但其值应在打印前转换为signed char或unsigned char”
哪个是正确的? 任何可靠的消息来源都说这个问题? (在这个意义上我们还应该用%d打印unsigned short
int,因为它可以被提升为int
?)。
正确的是*:
printf("%d",x);
这是因为printf()
是variadic函数的默认参数提升 。 这意味着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的答案 。
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"
长度修改器,可以补偿这种模糊性。 由于variadic参数的标准促销, x
应该被提升为int
或unsigned
, printf()
会在打印之前将其转换为unsigned char
。
printf("%hhu",x);
如果处理没有"hh"
的旧编译器或寻求高度可移植的代码,请使用显式转换
printf("%u", (unsigned) x);
相同的问题/答案适用于unsigned short
,期望INT_MAX >= USHRT_MAX
并使用"h"
而不是"hh"
。
unsigned char
和unsigned short
都可以安全地使用%u
打印。 默认参数提升将它们转换为int
或unsigned int
。 如果它们被提升为后者,一切都很好(格式说明符和传递的类型匹配),否则C11(n1570)6.5.2.2 p6,第一个项目符号适用:
- 一个提升类型是有符号整数类型,另一个提升类型是相应的无符号整数类型,并且该值可在两种类型中表示;
标准非常明确,默认参数提升适用于printf
的可变参数,例如,它再次提到(主要是无用的) h
和hh
长度修饰符(同上.7.21.6.1 p7,emph.mine):
hh
– 指定以下d
,i
,o
,u
,x
或X
转换说明符适用于signed char
或unsigned char
参数( 该参数将根据整数提升进行提升 ,但其值应转换为打印前signed char
或unsigned char
); […]
对于跨平台开发,我通常使用inttypes.h
绕过促销问题
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/inttypes.h.html
此标头(符合C99标准)定义了基本类型的所有printf类型。 所以如果你想要一个uint8_t(我强烈建议使用的语法而不是unsigned char)我会使用
#include #include uint8_t x; printf("%" PRIu8 "\n",x);