说我想要打印 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”
哪个是正确的?任何可靠的消息来源都说这个问题? (在这个意义上我们也应该打印 unsigned short
int与%d因为它可以被提升为 int
?)。
正确的是*:
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
可以表示原始类型的所有值 (受限制
通过宽度,对于位字段),该值被转换为a int
;
否则,它被转换为 unsigned int
。这些被称为
整数促销0.58) 所有其他类型的整数不变
促销活动。
这句话回答了你的第二个问题 unsigned short
(见下面的评论)。
*超过8位除外 unsigned char
(例如,它可能占据16位),请参阅@ chux's 回答。
正确的格式说明符 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"
长度修饰符,可以弥补这种歧义。应该x
升职 int
要么 unsigned
由于可变参数的标准促销, printf()
将其转换为 unsigned char
在打印之前。
printf("%hhu",x);
如果没有处理旧的编译器 "hh"
或寻求高度可移植的代码,使用显式转换
printf("%u", (unsigned) x);
相同的问题/答案适用于 unsigned short
,期待 INT_MAX >= USHRT_MAX
并使用 "h"
代替 "hh"
。
正确的是*:
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
可以表示原始类型的所有值 (受限制
通过宽度,对于位字段),该值被转换为a int
;
否则,它被转换为 unsigned int
。这些被称为
整数促销0.58) 所有其他类型的整数不变
促销活动。
这句话回答了你的第二个问题 unsigned short
(见下面的评论)。
*超过8位除外 unsigned char
(例如,它可能占据16位),请参阅@ chux's 回答。
正确的格式说明符 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"
长度修饰符,可以弥补这种歧义。应该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
转换说明符适用于a 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 <inttypes.h>
#include <stdint.h>
uint8_t x;
printf("%" PRIu8 "\n",x);