C ++编译错误? [英] C++ compilation bug?

查看:2477
本文介绍了C ++编译错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

  #include< iostream> 
#include< complex>
using namespace std;

int main(){
complex< int>三角洲;
complex< int> mc [4] = {0};

for(int di = 0; di <4; di ++,delta = mc [di]){
cout< di<< endl;
}

return 0;
}



我希望它输出0,1,2,3 ,但它输出一系列无穷的0,1,2,3,4,5 ...。



看起来像是比较<$ c



如果我只是注释掉, delta = mc [di] ,我得到0,1,2,3正常。无辜的作业有什么问题?



我使用 Ideone.com g ++ C ++ 14 with -O2 option。

解决方案

这是由于未定义的行为,你正在访问数组 mc 超出了你的循环的最后一次迭代。一些编译器可以围绕没有未定义的行为的假设执行积极的循环优化。逻辑类似于以下内容:




  • 访问 mc 未定义的行为

  • 假设没有未定义的行为

  • 因此 4 始终为true,否则 mc [di] 会调用未定义的行为



gcc启用优化并使用 -fno-aggressive-loop-optimizations 标志导致无限循环行为消失( 查看实时 )。尽管具有优化但没有-fno-aggressive-loop-optimizations 的实例展示了您观察到的无限循环行为。 p>

代码的godbolt活动示例显示了 di< ; 4 检查被删除并替换为无条件jmp:

  jmp .L6 

这几乎等同于 GCC pre-4.8 Breaks Broken SPEC 2006基准。这篇文章的意见是非常好,值得读。它注意到clang使用 -fsanitize = undefined 在这篇文章中无法重现的文章中使用 -fsanitize = undefined 查看实时 )。可能围绕优化器做出关于未定义行为的推断的最臭名昭着的错误是 Linux内核空指针检查删除



虽然这是一个积极的优化,但重要的是要注意,因为C ++标准说未定义的行为是:


这个国际标准没有要求的行为


这本质上意味着任何事情都是可能的, > emphasis mine ):




[...]允许未定义的行为
范围从完全忽略具有不可预测的结果,在翻译期间表现,或者以文档化的环境特征(有或没有发出
a诊断消息)执行
程序,以终止翻译或执行(...)


为了从gcc获取警告,我们需要移动 cout ,然后我们看到以下警告( see it live ):

 警告:iteration 3u调用未定义的行为[-Waggressive- ] 
for(di = 0; di <4; di ++,delta = mc [di]){}
^

将可能足以向OP提供足够的信息来确定发生了什么。这样的不一致是典型的我们可以看到与未定义的行为的类型的行为。要更好地理解为什么这种分心在面对未定义的行为时可能不一致为什么在根据未定义的行为进行优化时不会发出警告?是一个很好的阅读。



注意, -fno-积极循环优化记录在 gcc 4.8发行说明中。 / p>

I have the following code:

#include <iostream>
#include <complex>
using namespace std;

int main() {
    complex<int> delta;
    complex<int> mc[4] = {0};

    for(int di = 0; di < 4; di++, delta = mc[di]) {
        cout << di << endl;
    }

    return 0;
}

I expect it to output "0, 1, 2, 3" and stop, but it outputs an endless series of "0, 1, 2, 3, 4, 5, ....."

It looks like the comparison di<4 doesn't work well and always returns true.

If I just comment out ,delta=mc[di], I get "0, 1, 2, 3" as normal. What's the problem with the innocent assignment?

I am using Ideone.com g++ C++14 with -O2 option.

解决方案

This is due to undefined behavior, you are accessing the array mc out of bounds on the last iteration of your loop. Some compilers may perform aggressive loop optimization around the assumptions of no undefined behavior. The logic would be similar to the following:

  • Accessing mc out of bounds is undefined behavior
  • Assume no undefined behavior
  • Therefore di < 4 is always true since otherwise mc[di] would invoke undefined behavior

gcc with optimization turned on and using the -fno-aggressive-loop-optimizations flag causes the infinite loop behavior to disappear(see it live). While a live example with optimization but without -fno-aggressive-loop-optimizations exhibits the infinite loop behavior you observe.

A godbolt live example of the code shows the di < 4 check is removed and replaced with and unconditional jmp:

jmp .L6

This is almost identical to the case outlined in GCC pre-4.8 Breaks Broken SPEC 2006 Benchmarks. The comments to this article are excellent and well worth the read. It notes that clang caught the case in the article using -fsanitize=undefined which I can not reproduce for this case but gcc using -fsanitize=undefined does (see it live). Probably the most infamous bug around an optimizer making an inference around undefined behavior is the Linux kernel null pointer check removal.

Although this is an aggressive optimizations, it is important to note that as the C++ standard says undefined behavior is:

behavior for which this International Standard imposes no requirements

Which essentially means anything is possible and it notes (emphasis mine):

[...]Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).[...]

In order to get a warning from gcc we need to move the cout outside the loop and then we see the following warning (see it live):

warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
     for(di=0; di<4;di++,delta=mc[di]){ }
     ^

which would have likely been sufficient to provide the OP with enough information to figure out what was going on. Inconsistency like this are typical of the types of behavior we can see with undefined behavior. To get a better understanding of why such waring can be inconsitent in the face of undefined behavior Why can't you warn when optimizing based on undefined behavior? is a good read.

Note, -fno-aggressive-loop-optimizations is documented in the gcc 4.8 release notes.

这篇关于C ++编译错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆