Ily*_*hin 25 c bit-shift undefined-behavior language-lawyer
根据这个问题的答案:
E1 << E2的结果是E1左移E2位位置; 腾出的位用零填充.如果E1具有无符号类型,则结果的值为E1×2 E2,比结果类型中可表示的最大值减少一个模数.如果E1具有带符号类型和非负值,并且E1×2 E2可在结果类型中表示,那么这就是结果值; 否则,行为未定.
这似乎意味着1 << 31未定义.
但是,如果我使用,GCC不会发出警告1 << 31.它确实发出一个问题1 << 32.
链接
那是哪个呢?我误解了标准吗?海湾合作委员会有自己的解释吗?
chq*_*lie 22
否:1 << 31如果类型int只有31个值位,则具有未定义的行为.
1U << 31可以并且评估0x80000000类型unsigned int是否有32个值位.
在字节有8位的系统中,sizeof(int) == 4平均值int最多有31个值位,因此将1乘以31位是未定义的.相反,在一个系统上CHAR_BIT > 8,可以写1 << 31.
gcc如果提高警告级别,可能会发出警告.试试gcc -Wall -Wextra -W -Werror. clang会发出相同选项的警告.
为了解决麦克罗伊的言论,1 << 31并没有评估为INT_MIN可靠.它可能会在您的系统上提供此值,但标准并不保证它,实际上标准将此描述为未定义的行为,因此您不仅可以不依赖它,还应避免它以避免虚假错误.优化器通常利用潜在的未定义行为来删除代码并破坏程序员的假设.
例如,以下代码可能编译为一个简单的return 1;:
int check_shift(int i) {
if ((1 << i) > 0)
return 1;
else
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Godbolt的编译器探测器所支持的编译器都没有,但这样做不会破坏整合.
小智 17
GCC没有对此发出警告的原因是因为1 << 31 它在C90中是有效的(但是实现定义的),并且即使在现代C++中也是有效的(但是实现定义的).C90定义<<为一个位移,然后说对于无符号类型,其结果是乘法的结果,但对于有符号类型没有这样的东西,它隐含地使它有效并使其被一般的措辞覆盖,即按位运算符已实现已签名类型的定义方面.C++现在定义<<为与相应的无符号类型相乘,结果转换回有符号类型,也是实现定义的类型.
C99和C11确实使其无效(说明行为未定义),但允许编译器接受它作为扩展.为了与现有代码兼容,并在C和C++前端之间共享代码,GCC继续这样做,但有一个例外:您可以使用-fsanitize=undefined获取检测到的未定义行为来在运行时中止您的程序,并且这个行为可以处理1 << 31,但仅在编译为C99或C11时.
它会调用未定义的行为,正如其他答案/评论所解释的那样.但是,为什么GCC不发出诊断.
实际上有两件事可能导致左移的未定义行为(均来自[6.5.7]):
如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义.
如果E1具有带符号类型和非负值,并且E1×2 E2可在结果类型中表示,那么这就是结果值; 否则,行为未定义.
显然GCC检测到第一个(因为这样做很简单),但后者不是.
| 归档时间: |
|
| 查看次数: |
1924 次 |
| 最近记录: |