我的代码看起来像这样(显示完成的所有用法):
bool done = false;
for(int i = 0; i < big; i++)
{
...
for(int j = 0; j < wow; j++)
{
...
if(foo(i,j))
{
done = true;
break;
}
...
}
if(done) break;
...
}
任何编译器都会将其转换为:
for(int i = 0; i < big; i++)
{
...
for(int j = 0; j < wow; j++)
{
...
if(foo(i,j))
goto __done; // same as a labeled break if we had it
...
}
...
}
__done:;
注意:虽然我最感兴趣的是if(done)break;
被绕过并作为死代码删除,但我也对它是否被删除done
感兴趣共
答案 0 :(得分:14)
显然这取决于编译器。当您不确定时,最好的办法是查看编译器的汇编输出(所有流行的编译器都有一个开关)。即使您不熟悉汇编,也至少可以将调试版本与优化版本进行比较。
话虽如此,这是goto
不是一个坏主意的少数情况之一。随意使用它来打破内循环。
修改强>
在VS2010中尝试了以下内容,确实优化了外部条件:
bool done = false;
for(int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; j++)
{
if(i == 7 && j == 3)
{
done = true;
break;
}
}
if(done) break;
}
return 0;
答案 1 :(得分:7)
GNU编译器就是这样做的,从优化级别-O1开始(我在x86_64上使用gcc 4.5.1)
call _Z3fooii // al = foo(i,j)
testb %al, %al
jne .L14
...
其中.L14是放置在__done:
的确切位置的标签更好的问题可能是:哪个现代编译器不执行此优化?
答案 2 :(得分:4)
我不是想偷偷摸摸,但是......这有关系吗?一般来说,我认为最好让编译器完成他们的工作,并且这项工作是根据您的源代码生成“最佳”(注意“最佳”可能根据您的需要而变化)编译代码。您应该使用分析器和算法复杂性的良好工作知识来识别代码中的任何性能注意事项。
如果你只是好奇,那么请忽略这个评论。但如果你的意图是以某种方式优化你的代码,那么我认为有更好的途径。
答案 3 :(得分:1)
我已经尝试了以下GCC 4.2.1:
// Prevent optimizing out calls to foo and loop unrolling:
extern int big, wow;
bool foo(int,int);
void
bar()
{
int done = false;
for(int i = 0; i < big; i++)
{
for(int j = 0; j < wow; j++)
{
if(foo(i,j))
{
done = true;
break;
}
}
if(done)
break;
}
}
...它会直接与-O3
:
33: e8 fc ff ff ff call 34 <bar()+0x34> ; call to foo*
38: 84 c0 test %al,%al
3a: 74 e5 je 21 <bar()+0x21> ; next loop iteration
3c: 83 c4 10 add $0x10,%esp
3f: 5b pop %ebx
40: 5e pop %esi
41: 5d pop %ebp
42: c3 ret
***这是来自未关联的目标文件,call 34
实际上是对foo
的调用。