当前位置:文档之家› for循环结构的剖析

for循环结构的剖析

for循环是我最喜欢的循环结构了,本来以为我对for循环已经很了解了,但在最近是使用之中不断的出问题,所以我又对for循环进行了一次比较深入的“研究”,研究结果使我大吃一惊,不得不感叹,C语言真的是高深莫测啊!
好了,感慨完了,让我们从头开始来聊一聊这个最熟悉但又最难以捉摸的for循环吧。
for循环是C语言中最基本的循环结构了,其典型应用是在已知循环次数时,进行的一系列循环操作。基本语法格式举例如下:
for(i=0;i<=100;i++)
括号中有三个表达式,其中第一个表达式用来给循环计数器赋初值,第二个表达式用来判断是否满足循环条件,第三个表达式用来改变循环计数器的值。
当然,这只是最基本的用法,这三个表达式并非只能针对同一个变量,甚至,并非每个都必须出现,这只是在循环体的不同位置进行运算的三个普通表达式而已。例如下面,计算n的阶乘,直到大于100为止:
a=1;
for(i=1;a<=100;i++) a*=i;
另外,每个表达式的位置也并非只能放置一个表达式,要知道,C语言中有一种逗号表达式,用逗号将多个表达式分隔开,在处理上,当做一个表达式来对待,最右边的表达式运算结果即为整个表达式的值。基于此理论,上面的阶乘运算可以改写为下面的格式:
for(a=1,i=1;a<=100;i++) a*=i;
这样写有什么好处呢?当然绝不仅仅是为了扮酷,在结构上,能够将一个整体运算紧密的结合在一起,可以最大限度的减小程序修改时遗漏等失误。Ctrl+C和Ctrl+V应该在写程序及修改程序中经常用到吧,如果写成这样,在复制过程中想丢掉语句都难。
第二个表达式可以写成逗号表达式的形式吗?当然也可以,不过我现在先不举例,待会会和一些注意事项一起说明。现在我们先把for循环的结构剖析一下,看看for循环究竟是怎样运行的。
首先是第一个表达式,这个表达式虽然是在for循环的循环表达式中出现的,但却不在循环体内,其实是循环体前面紧邻循环体的一个表达式,这也是上面两个写法效果相同的原因。毕竟它本身就是在循环体外面的,前一个程序只是光明正大的给写在了外面。为了证实这一点,我们来看一下for循环的汇编代码(不同编译器可能会有所不同,这里是在Keil4.1下编译的,编译器版本是armcc 4.0.0.728,选择的处理器是8962,因此编译出来的汇编指令是ARM CortexM3的指令)。
第一种写法:
4: a=1;
0x000001A8 2101 MOVS r1,#0x01
5: for(i=1;a<=100;i++) a*=i;
0x000001AA 2201 MOVS r2,#0x01
0x000001AC E001 B 0x000001B2
0x000001AE 4351 MULS r1,r2,r1
0x000001B0 1C52 ADDS r2,r2,#1
0x000001B2 2964 CMP r1,#0x64
0x000

001B4 DDFB BLE 0x000001AE
6: }
第二种写法:
4: for(a=1,i=1;a<=100;i++) a*=i;
0x000001A8 2101 MOVS r1,#0x01
0x000001AA 2201 MOVS r2,#0x01
0x000001AC E001 B 0x000001B2

0x000001AE 4351 MULS r1,r2,r1
0x000001B0 1C52 ADDS r2,r2,#1
0x000001B2 2964 CMP r1,#0x64
0x000001B4 DDFB BLE 0x000001AE
5: }
可以看出,二者编译出来的汇编代码完全一样。在这里,B是跳转指令,在跳转指令下面是循环体。循环体代码如下:
0x000001AE 4351 MULS r1,r2,r1
0x000001B0 1C52 ADDS r2,r2,#1
0x000001B2 2964 CMP r1,#0x64
0x000001B4 DDFB BLE 0x000001AE
了解一些汇编的不难看出来(我也是在验证这个for循环时看了一点ARM汇编,我参考的文档是Cortex-M3 Technical Reference Manual),BLE是条件跳转,根据条件跳转到前面的某一行语句上,循环的基本写法。
C语言中对for循环的执行过程描述如下:首先计算一次表达式1的值(参考格式:for(表达式1;表达式2;表达式3),再计算表达式2的值,如果表达式2的值为true,则执行一次循环体,如果表达式2的值为false,则退出循环体。没执行完一次循环体后,计算表达式3的值,然后再计算表达式2的值,并根据表达式2的值决定是否继续执行循环体。
在这里表达式2需要在两个位置计算,一是刚进入循环时判断第一次循环是否执行,另外则是在每次执行完循环时判断是否进行下一次循环,一个位置是在整个循环体前,另一个位置是在表达式3之后。在编译过程中,为了减小程序体积,表达式2只在表达式3之后计算。同时在循环体前增加一个无条件跳转指令跳过整个循环体(包括表达式3)跳转到循环的结尾来做第一次判断。所以,for循环的执行是从最后的指令开始执行的。
总结一下,for循环中的三个表达式执行方式如下:表达式1在整个循环体的前面(循环体外)执行一次,表达式2为循环体的最后一组指令(可以有多个表达式组成,下同),表达式3为倒数第二组指令,在表达式2前面紧邻表达式执行。
注:关于循环体的定义,在C语言表达式中,for循环的三个表达式都不属于循环体,但是假如以汇编的跳转指令界定的话,表达式2和表达式3也应该属于循环体,毕竟它们也是以同样的次数循环执行的。以上只是为了说明我在文中使用的循环体名称,很久不玩汇编了,对一些定义也都忘记了,所以也可能官方定义不同。




by 柳叶舟 原文地址:http //bbs eeworld com cn/thread 289239 1 1 html




相关主题
文本预览
相关文档 最新文档