您的位置:首页 > 其它

深度剖解“IF表达式”底层实现过程

2017-07-20 22:15 155 查看
“if表达式”绝大多数c/c++以及其他编程语言的编程人员来说一点都不陌生,几乎每天写代码都会用到这个条件表达式!大多数程序员都知道if就是用来判断某一条件是否成立的,但是你知道if语句底层CPU是怎样执行的吗?编译器会把if表达式翻译成怎样的汇编代码吗?

补充一个问题:刚入编程这行业的新手容易犯的一个错误,就是在写if语句的时候容易把=(赋值表达式)和==(恒等于)混淆,恒等于的意思是需要表达式成立!是逻辑运算的意思,也就是说需要表达式的结果满足一定条件!

c/c++代码:

int main(void)

{

int Test_ = 5; //申请一个int类型的变量,变量名为Test_

if(Test_ == 5) //判断Test变量里的值是否是5

{

Hold water!

}

else

{

No Hold water!

}



汇编代码:

PUSH BP //将a变量入栈

MOV BP,SP //SP寄存器指向BP

MOV AX,101B //把5放进AX寄存器符号位省略

MOV BP,AX //把ax寄存器里面的值存入到BP指向的地址

SUB BP,-0//找到位于栈中变量a的起始位置

CMP BP,AX//与5(101)比较 此时ZF寄存器的值是1

JG No Hold water!//当BP里的值大于5时

JE Hold water!//当BP里的值等于5时

JL No Hold water!//当BP里的值小于5时

JNL No Hold water!//当BP里的值大于等于5时

JNG No Hold water!//当BP里的值小于等于5时

PUSH BP

首先将Test_变量压入栈,这里我要说一下为什么是PUSH BP 而不是 PUSH Test_? 因为BP是基址寄存器(基址指针)它保存了函数处于栈空间的入口地址!因为Test_处于函数的第一个位置所以PUSH BP也就是为Test_分配内存。

MOV BP,SP

将栈顶寄存器SP指向BP 。

MOV AX,101

将5放进ax寄存器,一般的翻译器都会将翻译成十六进制,这里我用二进制表示。

MOV BP,AX

将ax寄存器里面的5存放到BP指向的函数入口地址(也就是Test_的起始地址)为什么不直接把5放进BP指针指向的Test_变量起始地址上?学过汇编的应该都知道,地址寄存器是不能直接访问的,要通过媒介寄存器来访问!这里说的媒介就是一般寄存器,除了一般寄存器两个地址寄存器一样可以进行交互!

SUB BP,-0

把BP基址寄存器偏移地址指向Test_的起始地址

CMP BP,AX

通过CMP指令比较两个数,并根据比较结果设置相应ZF寄存器状态

根据ZF寄存器状态执行相应的指令

JG 大于

JE 等于

JL 小于

JNL 大于等于

JNG 小于等于

以上就是if语句底层执行过程,从分析结果来看,if语句会先处理括号里面的数在判断。

简单来说在if表达式里面做任何运算计算机都会执行

示例

if(Test_ = 3)

{

trutl


}

else

{

false

}

因为优先级的关系,在c语言里面被括号括起来的表达式优先级都会提高一个等级!编译器会优先编译括号里面的表达式,在去编译括号外的,也就是说:会先给Test_赋值3在去执行CMP指令

如果是赋值的话汇编代码是如下

MOV BP,011B

CMP BP //只要BP指向的那一块地址内存里的数大于1即执行JG命令

在计算机内部0/1代表高低电平,高电平对应的是开,低电平是关。

也就是说想让某个芯片运行就要向某个芯片发送高电平!

在操作系统中0即逻辑假1即逻辑真,无论是任何一款操作系统Linux,Windows还是安卓和ios都遵循这一逻辑。

最后建议大家在用if语句判断变量是否等于某个常数时可以这样写

if(5 == a)

这样就算少写一个等号在编译时也会报错因为常数不可赋值!

这里说一个关于左值右值的问题:

左值变量右值常数,常数是不能赋值的,因为编译器并没有为其分配内存。

也就是说没有内存的常数并不属于堆栈中,而是属于代码段中。

其实说是常数没有内存其实是占内存的,因为指令也需要内存来存放吖!

这里说下常数有个别名:也称为“立即数”。

立即数是存储于指令集中的并没有单独的内存空间,立即数的最大值是有限的,大小是取决于你电脑中的指令集。

比如arm的指令集是32位的,其中低位存指令、高位存立即数的二进制位。

那么这个立即数的MAX是4099,如果超出最大上限值编译器就会单独在栈中开辟一块空间,来存放这个立即数。

立即数的最大值取决于你计算机指令集的位数大小的一半!不同的处理器指令集对应的位数不同。比如arm的指令集是32位的早期的arm是16位的。

ps:本文章一部分是在地铁等候室里写的,有些地方说的可能不太仔细模糊凌乱!还请谅解,如果有写的不对的地方可以指出来,谢谢!

汇编哪一段代码是博主看着翻译的并不是编译器翻译的结果,因为当时在地铁等候室里没有电脑!

如果有翻译错的地方还请大家指出来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: