说我想要打印 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);