编译器是否允许删除像 Intel C++ 这样的无限循环?编译器用-O2吗?
以下测试代码在 VS 中无论是调试还是发布都能正确运行,在 GCC 中也能正确运行。对于带调试的 ICC,它也能正确执行,但在启用优化时则无法正确执行 (-O2
)。
#include <cstdio>
class tClassA{
public:
int m_first, m_last;
tClassA() : m_first(0), m_last(0) {}
~tClassA() {}
bool isEmpty() const {return (m_first == m_last);}
void updateFirst() {m_first = m_first + 1;}
void updateLast() {m_last = m_last + 1;}
void doSomething() {printf("should not reach here\r\n");}
};
int main() {
tClassA q;
while(true) {
while(q.isEmpty()) ;
q.doSomething();
}
return 1;
}
它应该停止在 while(q.isEmpty())
处。然而,当在 ICC(发布)下启用 -O2
时,它开始无限地“doSomething”。
由于这是单线程程序并且 isEmpty()
应该被评估为true
,我找不到 ICC 应该以这种方式运行的原因?我错过了什么吗?
The following testing code does correctly in VS either with debug or release, and also in GCC. It also does correctly for ICC with debug, but not when optimization enabled (-O2
).
#include <cstdio>
class tClassA{
public:
int m_first, m_last;
tClassA() : m_first(0), m_last(0) {}
~tClassA() {}
bool isEmpty() const {return (m_first == m_last);}
void updateFirst() {m_first = m_first + 1;}
void updateLast() {m_last = m_last + 1;}
void doSomething() {printf("should not reach here\r\n");}
};
int main() {
tClassA q;
while(true) {
while(q.isEmpty()) ;
q.doSomething();
}
return 1;
}
It is supposed to stop at while(q.isEmpty())
. When -O2
enabled under ICC (release), however, it starts to "doSomething" infinitely.
Since this is single-threaded program and isEmpty()
should be evaluated as true
, I can find no reason the ICC should behave in this way? Do I miss anything?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
由于
while (q.isEmpty()) ;
循环不包含可能导致外部可见副作用的语句,因此整个循环正在被优化以使其不存在。出于同样的原因:只要
i
不是易失性
(存储到易失性
对象是程序的“外部可见”效果)。在C语言中,是否允许通过这种方式优化掉无限循环实际上是一个争论的焦点(我不知道C++的情况如何)。据我所知,在这个问题上一直没有达成共识——聪明而有知识的人都站在了一边。
Because the
while (q.isEmpty()) ;
loop contains no statements that can ever cause an externally-visible side-effect, the entire loop is being optimised out of existence. It's the same reason that:could be optimised out of existence, as long as
i
was notvolatile
(stores tovolatile
objects are part of the "externally visible" effects of a program).In the C language, it is actually an outstanding bone of contention as to whether an infinite loop is allowed to be optimised away in this manner (I do not know what the situation is with C++). As far as I know, a consensus has never been reached on this issue - smart and knowledgeable people have taken both sides.
这听起来确实像一个错误。这是一个(非常疯狂的)猜测,关于什么推理可能会导致它......
内联后,它看到:
并且
的任何序列不重复执行任何操作; do some
可以简单地翻译为“做某事”。如果重复的部分是无限的(如本例所示),则该值会下降。但也许他们不会在故意无限循环的示例上测试其编译;-)。It sure sounds like a bug. Here's a (pretty wild) guess about what reasoning might have lead to it...
After inlining, it sees:
and any sequence of
do nothing repeatedly ; do something
can be translated to simply "do something". This falls down if the repeated part is endless (as in this case). But perhaps they don't test their compiling on examples that intentionally have endless looping ;-).您构建和运行的实际代码是否有可能在
while(q.isEmpty())
之后缺少分号?这肯定会导致下一行被无限调用。Any chance the actual code that you built and ran was missing the semicolon after
while(q.isEmpty())
? That would certainly result in the next line being called infinitely.顺便说一句,这个版本的 icc 可以满足您的需求。也就是说,它从不调用
doSomething()
。As a slight aside, this version of icc does what you want. That is, it never calls
doSomething()
.C++ 标准允许删除没有副作用的循环,即使它们不会终止:
请参阅此处的讨论:
http://blog.regehr.org/archives/161
The C++ standard allows loops without side-effects to be removed, even if they don't terminate:
See the discussion here:
http://blog.regehr.org/archives/161
最好的选择是将生成的二进制步骤放入其中并反汇编 main 函数并查看生成的程序集。并不是说您将能够看到错误,但您可以看到某些内容是否被优化。
Your best bet is to take the resulting binary step into it and dis-assemble the main function and see what assembly was generated. Not saying you will be able to see a bug, but you can see if something was optimized out.
我认为这可能是你的 gcc 版本。我在 4.4.2 下编译了你的程序,它的工作原理与应有的完全一样。
I think it may have been your version of gcc. I compiled your prog under 4.4.2 and it worked exactly as it should have.