难道不应该警告我 -INT_MIN 的未定义行为吗?

Shouldn't I be warned about undefined behavior with -INT_MIN?

提问人:einpoklum 提问时间:8/2/2021 最后编辑:einpoklum 更新时间:8/3/2021 访问量:70

问:

请考虑以下 C 程序:

#include <limits.h>

int main() {
  int x = INT_MIN;
  int y = -x;
  return y;
}

该程序具有未定义的行为,因为INT_MIN的否定是不可表示的;或者,成为一名语言律师——因为 C 标准是这么说的。

现在,编译器知道或可以知道,情况就是这样。然而 - GCC 和 clang 都没有对此发出警告,即使使用 -W -Wall -Wextra (GodBolt);只有清理未定义的行为才能在运行时捕获它。

为什么会这样?一般来说,试图证明 UB 在编译时发生的成本是否太高,因此编译器不会打扰?

gcc clang 编译器警告未 定义行为 ubsan

评论

0赞 Marc Glisse 8/3/2021
制作 const 并使用 g++(并且没有修改代码的清理程序),我确实收到警告。通常,在优化期间执行的这种警告(与解析器警告相反)会导致误报(它们在编译器不知道已死的死代码中经常发生),我不知道这是否是即使使用时我们也不会收到警告的原因。如果您找不到有关该主题的任何历史记录,您可以尝试向其中一个编译器提交错误......x-Wstrict-overflow=5 -O3
0赞 einpoklum 8/3/2021
@MarcGlisse:我认为也许还有一个更重要的根本原因,而不是关于死代码的警告。毕竟,应该清理自己的代码并删除未使用的部分......
0赞 Marc Glisse 8/3/2021
“死代码”在编译器的中间表示中,不一定在源文件中!当编译器内联函数、展开循环等时,它可以很容易地创建一些永远无法执行的代码片段的变体。但也许除了误报之外还有其他原因......
0赞 supercat 8/5/2021
@einpoklum:一些编译者急切地认为,即使是不打算移植的程序也永远不会收到导致它们执行标准描述为“不可移植或错误”的任何操作的输入,并且它允许实现“以环境特征的记录方式”进行处理,在这种情况下这样做是有用的。这种编译器认为,只有在接收到此类输入时才相关,并且会将其消除,即使以环境特征的方式处理输入会更有用,这些代码才会被删除。

答:

-1赞 supercat 8/3/2021 #1

当使用某些实现或配置时,此类构造将是安全的。当使用启用了优化但未启用优化的 clang 或 gcc 时,此类构造可能会导致其他地方的代码以不受普通因果律约束的方式进行无意义的处理。-fwrapv

用 C 标准的话来说,代码是不可移植的或错误的。从已公布的基本原理中可以清楚地看出,该标准希望该短语包括不可移植的结构,但在用于对旨在适用于低级编程的实现执行低级任务时是正确的。然而,该标准为编译器编写者提供了自由,其客户不会故意使用此类结构进行低级编程,在这种情况下,将它们视为“错误”,这比假设它们是故意的但不可移植的更有用。那些希望将他们的编译器卖给将使用它们的程序员的人将比委员会更了解他们的客户会故意使用哪些结构,因此没有必要让标准本身做出这样的区分。

然而,一些不受这种市场压力影响的编纂者却在不同的理念下运作,其中“不可移植或错误”一词的意思是“不可移植,因此是错误的”。因此,即使在整数溢出在机器代码级别永远不会产生任何副作用的平台上,这些编译器有时也可能会特意在确定整数溢出是不可避免的情况下不表现出有意义的行为,即使程序行为的任何方面都不会对计算结果产生任何因果关系。