unsigned short int i = 0;
printf("%u\n",~i);
为什么此代码在控制台中返回32位数字?它应该是16位,因为short是2个字节。
输出为4,294,967,295,应为65,535。
答案 0 :(得分:5)
%u
期待unsigned int
;如果您要打印unsigned short int
,请使用%hu
。
修改强>
Lundin是正确的,~i
在转移到int
之前会转换为printf
类型。由于传递给可变函数,i
也会转换为int
。但是,如果使用printf
转换说明符,unsigned short
会在打印前将参数转换回%hu
:
7.21.6.1 fprintf功能
...
3格式应为多字节字符序列,以其首字母开头和结尾 转移状态。格式由零个或多个指令组成:普通的多字节 字符(不是%
),不加改变地复制到输出流;和转换 规范,每个规范导致获取零个或多个后续参数, 根据相应的转换说明符转换它们(如果适用),以及 然后将结果写入输出流 ...
7长度修饰符及其含义如下:
...
h
指定以下d
,i
,o
,u
,x
或X
转换说明符适用于short int
或unsigned short int
参数(参数将会 已根据整数促销推广,但其价值应为 在打印前转换为short int
或unsigned short int
); 或者以下n
转换说明符适用于指向short int
参数的指针。
强调我的。
所以,行为不未定义;如果i
或~i
不是整数类型,则只会是未定义的。
答案 1 :(得分:4)
当您将参数传递给printf
且该参数的整数类型短于int
时,根据K& R参数提升规则将其隐式提升为int
。因此,您的printf
- 调用实际上就像:
printf("%u\n", (int)~i);
请注意,这是未定义的行为,因为您告诉printf
该参数具有unsigned
类型,而int
实际上是签名类型。将i
转换为unsigned short
然后转换为unsigned
以解决未定义的行为和您的问题:
printf("%u\n", (unsigned)(unsigned short)~i);
答案 2 :(得分:4)
N1570 6.5.3.3一元算术运算符p4:
〜运算符的结果是其(提升的)操作数的按位补码(即, 当且仅当转换后的操作数中的相应位为时,才会设置结果中的每个位 没有设置)。 对操作数执行整数提升,结果为 推广类型。 ......
小于int
的整数类型将提升为int
。如果sizeof(unsigned short) == 2
和sizeof(int) == 4
,则结果类型为int
。
还有,printf
转换说明符%u
需要unsigned int
,因此int
的表示形式被解释为unsigned int
。你基本上对编译器撒谎,这是未定义的行为。
答案 3 :(得分:3)
这是因为printf()
的参数是用文字放入堆栈的,因为printf内部无法知道参数是否很短。同样通过使用%u
格式,您只是声明您传递的是无符号数字。