有符号整数溢出是否定义了未定义的行为或实现?
#include <limits.h>
int main(){
int a = UINT_MAX;
return 0;
}
我这个 UB 或实现定义?
链接说它的 UB
https://www.gnu.org/software/autoconf/manual/autoconf-2.63/html_node/Integer-Overflow-Basics
允许 C/C++ 中的有符号整数溢出
链接说它的实现定义
http://www.enseignement.polytechnique.fr/informatique/INF478/docs/Cpp/en/c/language/signed_and_unsigned_integers.html
转换规则说:
否则,新类型是有符号的,值不能在其中表示;要么结果是实现定义的,要么引发实现定义的信号。
我们不是将 a 转换max unsigned value为 asigned value吗?
我所看到的方式,gcc 只是截断了结果。
回答
两个参考文献都是正确的,但它们没有解决相同的问题。
int a = UINT_MAX;不是有符号整数溢出的实例,此定义涉及从unsigned int到int具有超出类型范围的值的转换int。正如École polytechnique的网站所引用的,C 标准将行为定义为实现定义。
#include <limits.h>
int main(){
int a = UINT_MAX; // implementation defined behavior
int b = INT_MAX + 1; // undefined behavior
return 0;
}
以下是来自 C 标准的文本:
6.3.1.3 有符号和无符号整数
将整数类型的值转换为 以外的其他整数类型时
_Bool,如果该值可以用新类型表示,则不变。否则,如果新类型是无符号的,则通过重复加或减一个新类型可以表示的最大值来转换该值,直到该值在新类型的范围内。
否则,新类型是有符号的,值不能在其中表示;要么结果是实现定义的,要么引发实现定义的信号。
一些编译器有一个命令行选项来将有符号算术溢出的行为从未定义的行为更改为实现定义的行为:gcc并clang支持-fwrapv强制整数计算以 2 32或 2 64为模执行,具体取决于有符号类型。这阻止了一些有用的优化,但也阻止了一些可能破坏无辜代码的违反直觉的优化。请参阅此问题以获取一些示例:What do -fwrapv do?