signed integer overflow对编译器的影响

目录

  • 问题介绍
  • 相关资料
  • -fwrapc功能介绍
  • 附录

问题介绍

最开始接触这个问题,是在研究编译器对C和C++中的未定义行为的处理时看到的一篇文章。What Every C Programmer Should Know About Undefined Behavior#1/3
其中有一部分是对signed integer overflow类型的未定义行为进行介绍。
作者举了一个例子,如果考虑溢出的情况,那么对于不等式 i+1 > i,不一定是恒成立的,也即如果编译器不考虑这种情况,直接将i+1>i优化为true,就会造成部分例子的错误。同样的,对于x * 2 / 2和x也存在这样的问题。
对于无符号类型,这个问题则不存在,无符号类型的进位是通过循环进位(wrap)的形式进行的,也即对于最大的无符号整数,其+1将变为0。这也很好理解,因为无符号整数不存在最高位的符号位,因此如果一个无符号整数最大,即所有位上均为1,此时+1会变成所有位上均为0的情况。
为了处理因为signed integer overflow造成的undefined问题。编译器提供了一个支持,即通过-fwrapc将符号整数的进位问题从一个未定义行为转化成一个定义行为。
在上述链接中,作者提到了存在的问题是可能为-1的情况。

相关资料

我在CSDN上检索该-fwrapc命令,只找到了两篇文章,一篇是翻译一个溢出相关的blog,另一篇 是作者对一段程序添加-fwrapc前后出现的问题进行的展示。遗憾的是,该问题在g++的新版本中已经修复,目测是因为g++在优化过程中较为激进,没有考虑到溢出的情况。

-fwrapc功能介绍

在这篇文章中,作者分析了开启-fwrapc和fwrapc的区别,我提供了一个新的示例程序,在参考该作者的基础上证明了对于问题介绍部分的文章讲到的divide of INT_MIN by -1的情况同样可以解决。

#include 
#include 

int gt(int i) {
    return (i / -1) == i;
}

int main() {
    std::cout << gt(INT_MIN) << std::endl;
    // std::cout << (INT_MIN / -1 == INT_MIN); 
}

此代码在gcc13.2上,开启-fwrapc和不开启-fwrapc的结果不同。前者返回true因为编译器识别到了溢出,而后者返回false,因为编译器忽略了溢出的情况而直接分析-INT_MIN和INT_MIN,给出了false的回答。
感兴趣的同学,我附上Compiler Explorer的链接。

附录

我将问题介绍中的文章相关部分翻译如下:
It is worth noting that unsigned overflow is guaranteed to be defined as 2’s complement
(wrapping) overflow, so you can always use them. The cost to making signed integer overflow defined is that these sorts of optimizations are simply lost (for example, a common symptom is a ton of sign extensions inside of loops on 64-bit targets). Both Clang and GCC accept the “-fwrapv” flag which forces the compiler to treat signed integer overflow as defined (other than divide of INT_MIN by -1).

值得注意的是无符号溢出可以保证是2的补溢出(循环),所以你总可以使用他们。要使有符号整数溢出变成定义行为的开销,就是某些优化很简单的丢失了(举个例子,很明显的情况在64位机器上的循环中一堆符号扩展。Clang和GCC都接受-fwrapc命令使编译器将有符号整数溢出视为确定行为(除了INT_MIN除以-1的情况)。

对于文中提到的参考文献,我在此进行梳理。
[1]: 介绍C语言中的未定义行为的文章
https://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
[2]: 介绍fwrapc使用的文章
https://blog.csdn.net/superzmy/article/details/115746689?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170330973616800215066558%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=170330973616800215066558&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-115746689-null-null.142%5Ev96%5Epc_search_result_base6&utm_term=fwrapv&spm=1018.2226.3001.4187)
[3]: 介绍fwrapc原理的文章
https://www.jianshu.com/p/59757ae4b201

你可能感兴趣的:(编程语言,c++,c语言)