【问题标题】:Possible VS2012 compiler bug (maybe in Whole Program Optimization?)可能的 VS2012 编译器错误(可能在整个程序优化中?)
【发布时间】:2013-08-06 07:44:49
【问题描述】:

这可能是编译器错误吗?我的环境是:

  • Win7 专业版(64 位)
  • VS2012(更新 3)

我编译下面的微型控制台程序。 x64 位发布/调试版本工作正常。 x32 调试版本也可以正常工作。但是,x32 发布版本显示“BUG!”。

如果我禁用“整个程序优化”将解决问题。

有什么想法吗?

-

#include <string>
#include <iostream>


int main()
{
    std::string const buffer = "hello, world";
    std::string::size_type pos = 0;
    std::string::size_type previous_pos;


    while (pos != std::string::npos)
    {
        previous_pos = ++pos;
        pos = buffer.find('w', pos);
    } 


    if (previous_pos == std::string::npos)
    {
        std::cout << "BUG!!"<< std::endl;
    }

    return 0;
}

【问题讨论】:

  • 如果循环大约零次,则 previous_pos 未初始化。
  • 将 previous_pos 初始化为零时会发生什么?也许编译器基于它未初始化的事实做出了一些假设?
  • 另外,将 pos 的 pre-increment 更改为 post-increment 似乎可以让 bug 消失。
  • while (pos != std::string::npos) { previous_pos = ++pos; pos = buffer.find('w', pos); std::cout
  • 另外,将 previous_post 更改为 = pos 和 pos = buffer.find('w', pos++) 有一些有趣的结果。在调试中,previous_pos 将在 0 和 7 之间交替。在版本 0 和 8.... 再次,我在循环中使用 cout。

标签: c++ visual-studio-2012 compiler-optimization compiler-bug


【解决方案1】:

我也可以重现这个。当 bug 出现时,代码正在测试 eax 以确定是否输出“BUG”,这与它用于 'pos' 的寄存器相同。

17:         previous_pos = ++pos;

013C12E5 增加
...

21:     if (previous_pos == std::string::npos)

00301345 cmp eax,eax
00301347 jne main+0F6h (0301366h)

但是,如果您进行更改以尝试让优化器意识到它们是不同的,那么测试就不同了。如果我在循环体的末尾添加 ++previous_pos 那么它使用 ecx 作为 previous_pos 并且错误消失了:

22:     if (previous_pos == std::string::npos)

00361349 cmp ecx,eax
0036134B jne main+0FAh (036136Ah)

如果我将查找更改为 'pos = buffer.find('w', previous_pos);' (从 previous_pos 而不是 pos 搜索,它具有相同的值)然后它使用 ebx,并且 bug 再次消失:

21:     if (previous_pos == std::string::npos)

00191345 cmp ebx,eax
00191347 jne main+0F6h (0191366h)

因此,尽管有 'pos = buffer.find('w', pos);' 这一行,但优化器似乎错误地决定它可以对这两个变量都使用 eax可以将 pos 设置为与 previous_pos 不同的值。

【讨论】:

  • 那么添加cout语句会导致程序意识到不能使用同一个寄存器?关于我上面关于寄存器在调试中的 0 和 7 以及发布中的 0 和 8 之间交替的最后评论呢?
  • 感谢大家关注这个问题。似乎每个人都同意这确实是一个编译器错误,所以我想我现在将其标记为“已回答”以将其关闭。
猜你喜欢
  • 2022-11-10
  • 2012-11-10
  • 2014-12-26
  • 1970-01-01
  • 2021-05-28
  • 2013-05-24
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多