C语言控制流程的语句有if-else 语句、switch 语句、while循环、for循环等,先来看一个if-else 的例子。
main()
{
int x = 7;
int y = 9;
float z = 0;
if(x > y)
z = x + y;
else
z = x - y;
printf("%f", z);
return 0;
}
这段代码中由于x 和y 都是固定值,所以执行的肯定是else 分支。来看编译后的汇编代码(去掉不关心部分,后面同):
.section .rdata,"dr"
LC1:
.ascii "%f\0"
.text
_main:
mov DWORD PTR [ebp-4], 7
mov DWORD PTR [ebp-8], 9
mov eax, 0x00000000
mov DWORD PTR [ebp-12], eax
mov eax, DWORD PTR [ebp-4]
cmp eax, DWORD PTR [ebp-8]
jle L2
mov eax, DWORD PTR [ebp-8]
add eax, DWORD PTR [ebp-4]
push eax
fild DWORD PTR [esp]
lea esp, [esp+4]
fstp DWORD PTR [ebp-12]
jmp L3
L2:
mov edx, DWORD PTR [ebp-8]
mov eax, DWORD PTR [ebp-4]
sub eax, edx
push eax
fild DWORD PTR [esp]
lea esp, [esp+4]
fstp DWORD PTR [ebp-12]
L3:
fld DWORD PTR [ebp-12]
fstp QWORD PTR [esp+4]
mov DWORD PTR [esp], OFFSET FLAT:LC1
call _printf
mov eax, 0
leave
ret
由基础汇编知识以及上一篇内容很容易看出,实现if-else 语句用的是比较指令cmp 与各种条件转移指令。具体代码不再分析,由于出现了新的条件转移指令jle ,下面重新总结一下。
根据两个无符号数的比较结果判断转移的指令:
指令 转移条件 含义 英文表述
JA/JNBE DEST CF=0 AND ZF=0 无符号数A>B JMP above (not below or equal)
JAE/JNB DEST CF=0 无符号数A≥B JMP above or equal (not below)
JB/JNAE DEST CF=1 无符号数AB JMP greater (not less or equal)
JGE/JNL DEST SF=OF OR ZF=1 有符号数A≥B JMP greater or equal (not less)
JL/JNGE DEST SF≠OF AND ZF=0 有符号数A
以上参照百度百科词条“条件转移指令”。
C语言中其它控制流程的语句编译后也是基于同样的汇编指令,都是cmp 比较,然后各种转移。下面合起来看一个例子:
/* 各种控制流程语句:if-else-if; switch; while; for; do-while; break; continue; goto */
#include
int main()
{
// if-else 语句
int a = 7;
int c = getchar();
if(c >= '0' && c <= '9'){
c ++;
a += c;
printf("a = %d\n", a);
}else if(c == 'A'){
printf("is A\n");
}else{
printf("%d\n", c);
}
// switch 语句
c = getchar();
switch(c){
case 'A':
printf("AAA");
break; // break语句
case 'B':
printf("BBB");
case 'C':
printf("CCC");
break;
default:
printf("DDD");
break;
}
// while循环
while((c=getchar()) != 'q'){
printf("%d", c);
}
int i;
for(i=0; i<10; i++){
if(i==5)
continue; // continue语句
printf("%d", i);
}
// do-while循环
do{
printf("do-while\n");
break;
}while(1);
// for循环
for(;;){
for(i=0; i<100; i++){
printf("%d", i);
if(i==50)
goto somewhere; // goto语句
}
}
somewhere:
printf("end");
return 0;
}
编译后的汇编代码:
.section .rdata,"dr" //将后续的代码汇编进一个定名为.rdata的段。
LC0:
.ascii "a = %d\12\0"
LC1:
.ascii "is A\12\0"
LC2:
.ascii "%d\12\0"
LC3:
.ascii "AAA\0"
LC4:
.ascii "BBB\0"
LC5:
.ascii "CCC\0"
LC6:
.ascii "DDD\0"
LC7:
.ascii "%d\0"
LC8:
.ascii "do-while\12\0"
LC9:
.ascii "end\0"
.text //将后续语句汇编到编号为0的子段。
_main:
mov DWORD PTR [ebp-4], 7
call _getchar
mov DWORD PTR [ebp-8], eax
cmp DWORD PTR [ebp-8], 47
jle L2
cmp DWORD PTR [ebp-8], 57
jg L2
lea eax, [ebp-8]
inc DWORD PTR [eax]
mov edx, DWORD PTR [ebp-8]
lea eax, [ebp-4]
add DWORD PTR [eax], edx
mov eax, DWORD PTR [ebp-4]
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:LC0
call _printf
jmp L3
L2:
cmp DWORD PTR [ebp-8], 65
jne L4
mov DWORD PTR [esp], OFFSET FLAT:LC1
call _printf
jmp L3
L4:
mov eax, DWORD PTR [ebp-8]
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:LC2
call _printf
L3:
call _getchar
mov DWORD PTR [ebp-8], eax
mov eax, DWORD PTR [ebp-8]
mov DWORD PTR [ebp-16], eax
cmp DWORD PTR [ebp-16], 66
je L8
cmp DWORD PTR [ebp-16], 66
jg L11
cmp DWORD PTR [ebp-16], 65
je L7
jmp L10
L11:
cmp DWORD PTR [ebp-16], 67
je L9
jmp L10
L7:
mov DWORD PTR [esp], OFFSET FLAT:LC3
call _printf
jmp L12
L8:
mov DWORD PTR [esp], OFFSET FLAT:LC4
call _printf
L9:
mov DWORD PTR [esp], OFFSET FLAT:LC5
call _printf
jmp L12
L10:
mov DWORD PTR [esp], OFFSET FLAT:LC6
call _printf
L12:
call _getchar
mov DWORD PTR [ebp-8], eax
cmp DWORD PTR [ebp-8], 113
je L13
mov eax, DWORD PTR [ebp-8]
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:LC7
call _printf
jmp L12
L13:
mov DWORD PTR [ebp-12], 0
L14:
cmp DWORD PTR [ebp-12], 9
jg L18
cmp DWORD PTR [ebp-12], 5
jne L17
jmp L16
L17:
mov eax, DWORD PTR [ebp-12]
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:LC7
call _printf
L16:
lea eax, [ebp-12]
inc DWORD PTR [eax]
jmp L14
L18:
mov DWORD PTR [esp], OFFSET FLAT:LC8
call _printf
L20:
mov DWORD PTR [ebp-12], 0
L22:
cmp DWORD PTR [ebp-12], 99
jg L20
mov eax, DWORD PTR [ebp-12]
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:LC7
call _printf
cmp DWORD PTR [ebp-12], 50
jne L24
jmp L26
L24:
lea eax, [ebp-12]
inc DWORD PTR [eax]
jmp L22
L26:
mov DWORD PTR [esp], OFFSET FLAT:LC9
call _printf
mov eax, 0
leave
ret
上面这段虽然代码很长,但和前面的if-else 汇编代码基本没什么区别,就是跳转次数多了些而已。
好了,C语言的控制流程语句就先学到这里,下一篇开始学习第4章,函数与结构。