i++循环与i--循环的执行效率

本文探讨了两种不同循环语句的执行效率:for(i=n;i>0;i--)与for(i=0;i<n;i++)。通过分析CPSR的影响及实际的汇编代码对比,揭示了前者为何在某些情况下表现更优。
转载时请注明出处和作者联系方式
文章出处:http://www.limodev.cn/blog
作者联系方式:李先静 <xianjimli at hotmail dot com>

昨天同事问了我一个问题,有两个循环语句:

for(i = n; i > 0; i--)
{

}

for(i = 0; i < n; i++)
{

}

为什么前者比后者快?

我当时的解释是:

i--操作本身会影响CPSR(当前程序状态寄存器),CPSR常见的标志有N(结果为负), Z(结果为0),C(有进位),O(有溢出)。i > 0,可以直接通过Z标志判断出来。

i++操作也会影响CPSR(当前程序状态寄存器),但只影响O(有溢出)标志,这对于i < n的判断没有任何帮助。所以还需要一条额外的比较指令,也就是说每个循环要多执行一条指令。

(这是五年前tjww告诉我的,当时他在AVR上写一个LCD驱动程序,使用后者LCD会闪烁,使用前者则没有问题。)

为了确认我的理解是正确的,做了个实验:

int loop_dec(int n)
{
int i = 0;
int v = 0;

for(i = n; i > 0; i--)
v +=i;

return v;
}

int loop_inc(int n)
{
int i = 0;
int v = 0;

for(i = 0; i < n; i++)
v +=i;

return v;
}
用arm-linux-gcc编译,然后反汇编:

i--的循环条件:
4c: e51b3014 ldr r3, [fp, #-20]
50: e3530000 cmp r3, #0 ; 0x0
54: cafffff5 bgt 30

i++的循环条件:
b8: e51b3018 ldr r3, [fp, #-24]
bc: e1520003 cmp r2, r3
c0: bafffff4 blt 98
结果和我想象的并不一样,这是怎么回事呢?我想可能因为没有加优化选项,于是加上-O选项,结果变为:

i--的循环条件:
14: e2500001 subs r0, r0, #1 ; 0x1
18: 1afffffc bne 10

i++的循环条件:
3c: e2833001 add r3, r3, #1 ; 0x1
40: e1500003 cmp r0, r3
44: 1afffffb bne 38
这下没错了,果然少一个cmp指令。
<think>我们被要求使用中文回答,并且遵守LaTeX格式要求。用户的问题是关于for循环执行顺序以及++--运算符在for循环中的作用。 根据引用[2]中的描述,for循环执行顺序如下: for(sta1; sta2; sta3) { sta4; } 1. 进入循环执行sta1(仅执行一次,通常用于初始化循环变量) 2. 执行sta2(条件表达式),如果为真,则执行循环体sta4;如果为假,则跳出循环 3. 执行循环体sta4 4. 执行sta3(通常用于更新循环变量) 5. 回到第2步 关于++ii++的区别: - 在独立使用时(即不其他表达式结合),两者都是将变量i的值增加1。 - 但如果在表达式中使用,则: - ++i(前缀递增):先增加i的值,然后返回增加后的值。 - i++(后缀递增):先返回i的当前值,然后再增加i的值。 然而,在for循环的更新部分(即sta3)中,由于更新表达式是独立执行的(即不其他表达式结合使用),因此无论是写i++还是++i,其效果都是将i的值增加1,并且对于循环执行顺序结果没有影响。 引用[1][3][4]都提到,在for循环的第三个表达式中,使用i++++i在结果上是一样的,但引用[1][3]提到在效率++i可能略高(在C++中,对于自定义类型,后缀递增需要返回一个临时对象,而前缀递增则直接返回引用,因此前缀递增效率更高)。但在基本类型(如int)上,编译器通常会将两者优化为相同的机器码,因此没有区别。 另外,用户还提到了--运算符,它++类似,只是将增加变为减少。 因此,在for循环中,更新部分无论是i++++i还是i+=1(引用[4]中也有提到),对于循环执行结果都是一样的。 总结: 1. for循环执行顺序:初始化->条件检查(真则进入循环体)->执行循环->执行更新表达式->再次条件检查... 2. 在for循环的更新表达式中,++ii++的作用都是将循环变量增加1,且执行效果相同(对于基本类型)。同理,--运算符也是如此。 现在,根据要求,我们需要生成相关问题。 </think> ### for循环执行顺序及`++`/`--`运算符的作用 #### 1. **for循环的标准执行顺序** for循环的结构为: `for(初始化; 条件; 更新) { 循环体 }` 具体执行流程如下(以`for(sta1; sta2; sta3) { sta4 }`为例): 1. **初始化**(`sta1`):仅在循环开始时执行一次(如`int i = 0`)[^2]。 2. **条件检查**(`sta2`):若为真(如`i < 10`),执行循环体`sta4`;若为假,退出循环[^2][^3]。 3. **执行循环体**(`sta4`):运行循环内部的代码。 4. **更新表达式**(`sta3`):执行迭代操作(如`i++`)[^2]。 5. **重复步骤2-4**,直到条件为假。 #### 2. **`++i``i++`在for循环中的作用** - **共同点**: 在for循环的**更新部分**(`sta3`),`i++``++i`最终都会使`i`的值增加1,**循环结果完全相同**(如输出相同的序列)[^1][^4]。 示例: ```javascript // 两者输出均为 0,1,2,3,4 for (let i=0; i<5; i++) { console.log(i); } // i++ for (let i=0; i<5; ++i) { console.log(i); } // ++i ``` - **区别**(理论层面): - `i++`(后缀):先返回`i`的当前值,再自增。 - `++i`(前缀):先自增,再返回新值。 但在for循环的更新部分,**返回值未被使用**,因此实际效果一致[^1][^4]。 - **效率差异**: 对于基本类型(如`int`),编译器会优化为相同效率;对于自定义对象(如C++迭代器),`++i`可能略高效(避免临时对象创建)。 #### 3. **`--`运算符的类似行为** 在递减循环中同理: ```java // 两者均输出 4,3,2,1,0 for (int i=4; i>=0; i--) { System.out.println(i); } // i-- for (int i=4; i>=0; --i) { System.out.println(i); } // --i ``` `i--``--i`在更新部分同样不影响循环结果。 #### 4. **关键注意事项** - **避免在条件/循环体中混用自增/自减**: 若在条件(`sta2`)或循环体(`sta4`)中使用`i++`/`++i`,结果可能不同(因返回值被使用)。 例如: ```java int i=0; while(i++ < 5) { ... } // 判断后自增,循环内i从1开始 while(++i < 5) { ... } // 自增后判断,循环内i从1开始但条件不同 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值