GCC 优化忽略循环条件
Posted
技术标签:
【中文标题】GCC 优化忽略循环条件【英文标题】:GCC optimalizations ignore for loop condition 【发布时间】:2021-07-05 15:17:32 【问题描述】:所以我写了这段代码:
#include <iostream>
constexpr
int fibonacci (int n)
int a = 0;
int b = 1;
for(auto i = 0; i < n; i++)
b += a;
a = b - a;
return b;
template<int N, int (T)(int)>
struct array
using type = decltype(T(0));
constexpr array() : arr()
for (auto i = 0; i < N; ++i)
arr[i] = T(i);
const type &operator[](int i) const return arr[i];
private:
type arr[N];
;
int main()
constexpr auto x = array<10, fibonacci>();
for (int i = 0; i < 11; i++)
std::cout << i << " " << x[i] << std::endl;
如果没有优化,它会按预期工作,打印 11 个值,最后一个是随机值。但是,一旦我移至 -O2,我就会随机获得一长串数字,其中包含崩溃和分段错误。 我在 godbolt.org (https://godbolt.org/z/4MqjbPbxE) 上检查了这个结果,它似乎不是问题,例如,clang。
我的问题是,这是 gcc 中的错误吗?为什么优化会删除/不检查 for 循环中的条件?
【问题讨论】:
索引越界是 UB。在不同的优化级别得到不同的结果是 UB 一个完全合理的结果。array<10, fibonacci>
让我很困惑。我以为它应该是std::array
。
如果 i >= 10
那么你有未定义的行为。允许编译器注意到这一点,并假设i < 10
始终为真。有了这个假设,i < 11
就是true
。
为什么会做出这样的假设?速度。它需要测试的东西少了一件。程序要做的越少,它就越快。您的代码不是计算机要执行的指令列表。它是对行为的描述。编译器的工作是接受该行为并生成指令列表。优化级别越高,编译器将花费更多时间寻找更快的方法来产生所描述的行为,并且它会在不改变行为的情况下对您的代码做任何想做的事情。如果你描述的行为甚至有点错误......
【参考方案1】:
您正在通过使用超出范围的x[i]
来调用未定义的行为。
再分配一个以避免超出范围的访问。
换句话说,
constexpr auto x = array<10, fibonacci>();
应该是
constexpr auto x = array<11, fibonacci>();
定义常量以避免拼写错误更好:
int main()
constexpr int num = 11;
constexpr auto x = array<num, fibonacci>();
for (int i = 0; i < num; i++)
std::cout << i << " " << x[i] << std::endl;
【讨论】:
【参考方案2】:修复检查索引。
for (int i = 0; i ; i++)
【讨论】:
以上是关于GCC 优化忽略循环条件的主要内容,如果未能解决你的问题,请参考以下文章