3 回答
TA贡献1796条经验 获得超7个赞
这是由于未定义的行为所致,您mc在循环的最后一次迭代中超出范围访问数组。一些编译器可能会围绕没有未定义行为的假设执行主动循环优化。逻辑将类似于以下内容:
mc越界访问是未定义的行为
假设没有未定义的行为
因此di < 4始终为真,否则mc[di]会调用未定义的行为
启用了优化功能的gcc并使用该-fno-aggressive-loop-optimizations标志会导致无限循环行为消失(参见live)。虽然有优化但没有-fno-aggressive-loop-optimizations的实时示例展示了您观察到的无限循环行为。
甲代码godbolt活示例示出了di < 4检查移除并用无条件JMP代替:
jmp .L6
这几乎与GCC 4.8之前的Breaks Breaked SPEC 2006 Benchmarks中概述的情况相同。对本文的评论非常好,非常值得阅读。它注意到clang在文章中抓住了这种情况-fsanitize=undefined,我无法用这种情况来重现这种情况,而gcc使用了这种情况-fsanitize=undefined(请参见实况)。关于优化程序的最臭名昭著的bug可能是对未定义行为的推断,这是Linux内核空指针检查删除。
尽管这是一项激进的优化,但必须注意,正如C ++标准所说,未定义的行为是:
本国际标准没有规定的行为
从本质上讲,这意味着一切皆有可能,并指出(强调我的观点):
[...]允许的不确定行为范围从完全忽略具有不可预测结果的情况到在翻译或程序执行过程中以环境特征的书面方式记录的行为(带有或不带有诊断消息),终止翻译或执行(带有诊断消息的发布)。[...]
为了从gcc获得警告,我们需要将cout循环移到外部,然后我们看到以下警告(实时查看):
warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
for(di=0; di<4;di++,delta=mc[di]){ }
^
这可能足以为OP提供足够的信息,以找出正在发生的事情。像这样的不一致是我们在未定义行为中可以看到的典型行为类型。更好地理解为什么在面对未定义行为时这种警告会变得不一致,为什么在基于未定义行为进行优化时为什么不发出警告?是一本好书。
注意,-fno-aggressive-loop-optimizations在gcc 4.8发行说明中有记录。
TA贡献1799条经验 获得超9个赞
这是因为di ++在循环的最后一次运行中执行。
例如;
int di = 0;
for(; di < 4; di++);
// after the loop di == 4
// (inside the loop we see 0,1,2,3)
// (inside the for statement, after di++, we see 1,2,3,4)
当di == 4时,您正在访问mc [],因此这是一个超出范围的问题,有可能破坏堆栈的一部分并破坏变量di。
一个解决方案是:
for(int di = 0; di < 4; di++) {
cout << di << endl;
delta = mc[di];
}
- 3 回答
- 0 关注
- 591 浏览
添加回答
举报