流程控制的底层实现

358 浏览发布于 作者 zouyang (欢迎转载-请注明出处链接)留下评论分享按钮

代码被编译后,指令一条接着一条顺序的执行,是我们过去常见的直线代码的行为。
现在的高级语言中,加入了流程控制语句。比如条件语句、循环语句和分支语句。
这些流程控制语句,可以让指令有条件的执行。流程控制语句被编译为底层语言时,可以通过指令进行跳转,比如jump指令可以改变一组机器代码指令的执行顺序,jump指令指定控制应该被传送到程序的哪个其它部分,可以是依赖于某个测试的结果。

 

机器代码指令提供2种基本的低级机制来实现有条件的行为:

1、测试数据值
2、根据测试的结果来改变控制流和数据流

 

如何测试数据值:
在计算机硬件中,除了整数寄存器,CPU还维护着一组单个位的条件吗(condition code)寄存器。该寄存器存储了最近的算数或者逻辑操作的属性值。计算机通过检测这些寄存器的属性值来执行条件分支指令。最常用的条件码有:

CF(进位标志)
ZF(零标志)最近的操作得出的结果为0
SF(符号标志)最近的操作得到的结果为负值
OF(进位标志)最近的操作导致一个补码溢出

 

汇编指令会根据编译结果设置条件码,以便后续指令对条件码的读取访问。
访问条件吗时,通常条件码不会被直接读取,常用访问的方法为3种:

1、可以根据条件码的组合,将一个字节设置为0或者1;(比如利用sete指令)
2、可以条件跳转到程序的某个其他部分;
3、可以有条件的传送数据。

 

控制流是实现有条件行为的更通用和更常见的方法,如何改变控制流:
例如,c语言中的语句和机器代码的指令都是按照它们在程序中的出现的次序,顺序执行的,用jump指令可以改变一组机器代码指令的执行顺序,在汇编代码中,跳转的目的地通常用一个标号(label)指明,jump指令指定控制应该被传递到程序的其他哪个位置,可能是依赖于某个测试结果。编译器必须产生指令序列,这些指令序列构建在这种实现C语言控制结构的低级机制之上。

 

 

PS:

对于循环控制,汇编中没有相应的指令存在,而是用条件测试和跳转组合起来实现循环的效果。

注意机器代码如何区分有符号和无符号值很重要:比如与C语言不同,机器代码不会将每个程序值都和一个数据类型联系起来。相反,大多数情况下,机器代码对于有符号和无符号两种情况都使用一样的指令,这是因为许多算数运算对于无符号和补码算术都有一样的位级行为。有些情况需要使用不同的指令来处理有符号和无符号操作,例如,使用不同版本的右移、除法和乘法指令,以及不同的条件码组合。

switch语句的由来,可以追溯到FORTRAN语言(1962)的 go to 语句。
switch语句可以根据一个整数索引值进行多重分支。处理具有多种可能结果的测试时,这种语句特别有用。它们不仅提高了代码的可读性,而且使用跳转表(jump table)这个数据结构使用实现更加高效。跳转表是一个数组,表项i是一个代码段的地址,这个代码段实现当switch索引值等于i时程序应该执行的动作。程序代码用于索引值来执行一个跳转表内的数组引用,确定跳转指令的目标。
和使用一组很长的if-else相比,使用跳转表的优点是执行switch语句的时间与switch的case数量无关。GCC根据switch语句中case的数量和case中值的稀少程序来翻译开关语句。当case数据比较多(例如4个以上),并且值的范围跨度比较小时,就会使用跳转表。从中也看出了,当条件很多时,尽量使用switch替代if else ,这样会带来性能的提升。当然这个也适用于js的。

想要打赏,请点击这里

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注