Riv*_*all 6 c bit-shift bitwise-operators implicit-conversion visual-studio-code
我试图在int, char, short, long
不使用头文件的情况下打印最小值<limit.h>
.所以按位操作将是一个不错的选择.但有些奇怪的事发生了
该声明
printf("The minimum of short: %d\n", ~(((unsigned short)~0) >> 1));
Run Code Online (Sandbox Code Playgroud)
给我
The minimum of short: -32768
Run Code Online (Sandbox Code Playgroud)
但声明
printf("The minimum of short: %d\n", ~((~(unsigned short)0) >> 1));
Run Code Online (Sandbox Code Playgroud)
给我
The minimum of short: 0
Run Code Online (Sandbox Code Playgroud)
这种现象也发生在char
.但它不会发生在long, int
.为什么会这样?
值得一提的是我使用VS Code作为我的编辑器.当我unsigned char
在语句中移动光标时
printf("The minimum of char: %d\n", (short)~((~(unsigned char)0) >> 1));
Run Code Online (Sandbox Code Playgroud)
它给了我一个提示,(int) 0
而不是(unsigned char)0
我所期望的.为什么会这样?
首先,您的代码都不是真正可靠的,也不会达到预期效果.
printf
并且所有其他变量参数长度函数都有一个功能失调的"功能",称为默认参数提升.这意味着传递的参数的实际类型经过静默促销.小整数类型(例如char
和short
)被提升为int
已签名的.(并且浮动被提升为双倍.)Tl;博士:printf
是一个坚果功能.
因此你可以在你想要的各种小整数类型之间进行转换int
,到最后仍然会有一个提升.如果您为预期的类型使用正确的格式说明符,则没有问题,但是您没有使用%d
它int
.
此外,与~
C中的大多数运算符一样,运算符执行其操作数的隐式整数提升.请参阅隐式类型提升规则.
话虽这么说,这一行~((~(unsigned short)0) >> 1)
做了以下几点:
0
类型的文字int
并转换为unsigned short
.unsigned short
回来int
.int
值的按位补码0
.这是0xFF...FF
十六进制,-1
十进制,假设是2的补码.右移此方法int
1.在此处,您可以在移动负整数时调用实现定义的行为.C允许这导致逻辑移位=零移位,或算术移位=符号位移位.从编译器到编译器和非可移植的结果不同.
无论0x7F...FF
是逻辑移位还是0xFF...FF
算术移位,都可以获得.在这种情况下,它似乎是后者,这意味着你-1
在转换后仍然有小数.
0xFF...FF
=的按位补充-1
和得到0
.short
.还是0
.int
.还是0
.%d
期望a int
并因此打印.unsigned short
印有%hu
和short
有%hd
.使用正确的格式说明符应该撤消默认参数提升的效果.建议:研究隐式类型提升并避免在具有签名类型的操作数上使用按位运算符.
要简单地显示各种签名类型的最低2的补码值,您必须使用无符号类型做一些技巧,因为对其签名版本的按位运算是不可靠的.例:
int shift = sizeof(short)*8 - 1; // 15 bits on sane systems
short s = (short) (1u << shift);
printf("%hd\n", s);
Run Code Online (Sandbox Code Playgroud)
这会将无符号整数1u
转换为15位,然后将其结果转换为short,以某种"实现定义的方式",这意味着在两个补码系统上,您最终将0x8000转换为-32768.
然后给出printf
正确的格式说明符,你将从那里得到预期的结果.