还是说这一切只是关于语义学?
还是说这一切只是关于语义学?
简短回答:不,它们完全相同。
理论上可能取决于编译器;一个非常糟糕的编译器可能会做些微不同的事情,但我会感到惊讶。
只是为了好玩,这里有两个变量,使用x86 gcc版本4.3.3作为Ubuntu附带的编译器,对我而言,它们编译成完全相同的汇编代码。您可以在linux上使用objdump检查最终二进制文件生成的汇编代码。
int main() { #if 1 int i = 10; do { printf("%d\n", i); } while(--i); #else int i = 10; for (; i; --i) printf("%d\n", i); #endif }
编辑: 这里有一个“苹果和苹果”while循环示例,它也编译成相同的汇编代码:
while(i) { printf("%d\n", i); --i; }
for (int i = 0; i < 10; i++)
{
...
}
并且int i = 0;
do
{
...
i++;
}
while (i < 10);
会生成完全相同的代码,或者(正如Neil在评论中指出的那样)多一个 jmp,但这不会对性能产生足够大的影响而值得担心。
没有语义差异,也不需要编译差异。但这取决于编译器。所以我尝试了g++ 4.3.2、CC 5.5和xlc6。
g++、CC是相同的,而xlc则不同
xlc中的差别在于初始循环进入点。
extern int doit( int );
void loop1( ) {
for ( int ii = 0; ii < 10; ii++ ) {
doit( ii );
}
}
void loop2() {
int ii = 0;
while ( ii < 10 ) {
doit( ii );
ii++;
}
}
XLC OUTPUT
.loop2: # 0x00000000 (H.10.NO_SYMBOL)
mfspr r0,LR
stu SP,-80(SP)
st r0,88(SP)
cal r3,0(r0)
st r3,64(SP)
l r3,64(SP) ### DIFFERENCE ###
cmpi 0,r3,10
bc BO_IF_NOT,CR0_LT,__L40
...
enter code here
.loop1: # 0x0000006c (H.10.NO_SYMBOL+0x6c)
mfspr r0,LR
stu SP,-80(SP)
st r0,88(SP)
cal r3,0(r0)
cmpi 0,r3,10 ### DIFFERENCE ###
st r3,64(SP)
bc BO_IF_NOT,CR0_LT,__La8
...
while
循环中变量的作用域比for
循环头声明的变量的作用域更广。因此,如果保持一个变量的生存时间会产生性能影响,则在选择使用while
循环还是for
循环时(不要将while
循环包裹在{}中以减少其变量的作用域),将会产生性能影响。for
循环,那么将采用快速路径,但是使用两个while
循环将采用慢速路径。类似地,如果对象很大(造成更多缓存流量)或使用系统资源,则可能会产生性能影响。但我无法想到一个真正的例子,说明这将有所不同。使用循环展开进行优化的编译器可能只在for循环情况下执行此操作。
两者是等价的,这只是语义上的区别。
唯一的区别可能在于do... while结构中,您将条件的评估推迟到体之后,因此可能节省1次评估。
i = 1; do { ... i--; } while( i > 0 );
for( i = 1; i > 0; --i )
{ ....
}
我是一名编译器开发者。我们将所有的“结构化”控制流(如if
、while
、for
、switch
、do
...while
)都编译成条件和无条件分支语句,然后分析控制流图。由于C编译器必须处理一般的goto
语句,所以最简单的方法是将所有内容都简化为分支和条件分支指令,然后确保处理这种情况。 (C编译器不仅要处理手写代码,还要处理自动生成的代码,其中可能有许多goto
语句。)
理想情况下应该是相同的,但最终取决于您的编译器/解释器。为了确保,您必须测量或检查生成的汇编代码。
有可能存在差异的证明:这些行使用cc65生成不同的汇编代码。
for (; i < 1000; ++i);
while (i < 1000) ++i;
不会。如果它们执行的是相同的操作,它们将编译成相同的代码 - 就像你所说的,这关乎语义。选择最能表达你想要表达的内容的那个。
continue在for和while中的行为不同:在for中,它改变计数器的值,在while中,通常不会改变计数器的值