为什么用c语言程序中的if语句实现从1加到100最后的结果是负数,编程实现从 1 加到 100 和从 100 加到 1 两个程序,哪个更快?为什么?...

原标题:编程实现从 1 加到 100 和从 100 加到 1 两个程序,哪个更快?为什么?

这是一个非常有趣的问题——而且也一直以来都很有争论。

认为“100加到1比1加到100”快的人,往往是基于这样一个事实:

jnz指令要明显快于cmp之后再jne

但是,这里有一个问题:编译器是否真的会把循环中的“不等于零”用nz指令来替换?

这里以C语言为实验对象。

好的,我现在在wsl上运行了gcc (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0

然后,用下面这段程序作为例子。

int sum;

int i;

int main(){

sum=0;

for(i=100;i!=0;i--)

sum+=i;

return 0;}

一个很简单的C程序。

我们用gcc来进行一下汇编。

gcc -O0 -S 1.c

好的,我猜不会有多少人愿意看……那就摘一下重点吧。

比较的地方的汇编如下:

movl i(%rip), %eax

testl %eax, %eax

jne .L3

而对于“从1加到100”而言,这一段则是

movl i(%rip), %eax

cmpl $100, %eax

jle .L3

并没有本质的区别。

为了保险起见,我们把循环中的

for(i=100;i!=0;i--)

改成

for(i=101;--i;)

于是,对比输出的汇编结果,除了循环体内的减法操作跑到了比较的地方之外,并没有更多的差别。

那么,如果打开/O1呢…会不会把nz这种东西优化进来

movl $5050, sum(%rip)

当我没说…

于是现在,我们使用msvc试一试。(19.16.27030.1)

cl /Od /FAs /c /Fonul 1.c

和刚才类似地,对于一路减下去的做法,汇编里依然多了个cmp指令

cmp DWORD PTR i, 0

je SHORT $LN3@main

而,如果是一路加上来,比较也并不会复杂很多

cmp DWORD PTR i, 100 ; 00000064H

jg SHORT $LN3@main

至于那种非要把--i放到循环条件里的…enmmm…您别说,还真的少了一行汇编…

我找了半天才看出来差在哪…

别人是先jmp到循环条件那里检查一下…不知道为啥,到了这里就是一个大循环…

不过…要执行上千行汇编的事…您给我说这一行jmp…不太好吧…

好的,看到有人说到了“上古时代”的编译器会有这种特性。

于是在DOSBOX中运行Turbo C 1.0进行实验。

TCC -S 1.c

一如既往,同样的行数,同样的快乐。

cmp word ptr dgroup:_i,0

jne @4

cmp word ptr dgroup:_i,100

jle @4

然而,在最后一种“奇葩”方法的测试中,我们终于如愿以偿收获了惊喜。

dec word ptr dgroup:_i

jne @4

在循环体内,确实就像想象的那样,少了一个cmp指令。

不过先不要急着下结论。我们继续我们的实验。

这次我们用刚刚下载的icc来测试(Version 19.0.3.203 Build 20190206)

test eax, eax ;5.15

je .B1.4 ; Prob 50% ;5.15

cmp eax, 100 ;5.13

jg .B1.4 ; Prob 50% ;5.13

而--i的做法这次…

我看了好半天…有点没看明白为什么会出现这种智障操作…

mov DWORD PTR [rbp], eax ;5.14

mov eax, DWORD PTR [rbp] ;5.14

mov DWORD PTR [i], eax ;5.14

mov eax, DWORD PTR [rbp] ;5.14

不过从结果上来看…它每次循环比另外两种写法要多执行两条语句…

以后我想做一下其它语言和编译器的测试

不过就目前的结果来看…

这名学生完全可以问面试官具体的架构环境编译器参数…

嗯,如果面试官认为没开优化的编译器都可以…那么…

“老师,您预习编译原理了吗?”返回搜狐,查看更多

责任编辑:

你可能感兴趣的:(为什么用c语言程序中的if语句实现从1加到100最后的结果是负数,编程实现从 1 加到 100 和从 100 加到 1 两个程序,哪个更快?为什么?...)