我知道两种方式生成的汇编代码肯定不同,但是没有预想到两个程序的行为表现也不同。
if
的版本一切正常(显示A
→按下X键
→显示BXCA
→按下Y键
→显示BYCA
→按下4号键
→B一闪而过
→执行return show_system_info()语句,当前页被刷新
)switch
的版本却表现为(显示A
→按下X键
→显示BXCA
→按下Y键
→显示BYCA
→按下4号键
→B一直显示,程序卡住了
)
附上代码和编译结果:
$ cat > hello.c <<EOF
int
show_system_info(void)
{
for (;;) {
putchar('A');
// 未按键时阻塞
// 按键后返回按键编号
// 对于字母按键,返回 ASCII 码
// 另有 F1 ~ F6 的按键,返回 -1 ~ 4 的整数(不是ASCII码)
int g = get_key();
putchar('B');
#ifdef NDEBUG
switch (g) {
// 注:可以看到每个 case 执行的都是跳转指令,
// 因此将 break 省略。经我测试,即使加上所有
// 的 break 语句,也会在编译器优化中被忽略掉,
// 得到的汇编代码与 switch.s 完全相同。
case 1:
case 3:
return show_freq_config(0);
case 2:
return show_freq_config(1);
case 4:
return show_system_info();
case -1:
return 0;
case 0:
continue;
default:
putchar(g);
}
#else
if (g == 1 || g == 3) {
return show_freq_config(0);
} else if (g == 2) {
return show_freq_config(1);
} else if (g == 4) {
return show_system_info();
} else if (g == -1) {
return 0;
} else if (g == 0) {
continue;
} else {
putchar(g);
}
#endif
putchar('C');
}
}
EOF
$ export CFLAGS='-std=c99 -Os -mtune=arm920t -mcpu=arm920t -mlittle-endian -fomit-frame-pointer -msingle-pic-base -fpic -mpic-register=r10 -msoft-float'
$ arm-elf-gcc $CFLAGS -S -c hello.c -o if.s
$ arm-elf-gcc $CFLAGS -D NDEBUG -S -c hello.c -o switch.s
$ cat if.s
.file "hello.c"
.text
.align 2
.global show_system_info
.type show_system_info, %function
show_system_info:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
mov ip, sp
stmfd sp!, {r4, fp, ip, lr, pc}
sub fp, ip, #4
.L20:
mov r0, #65
bl putchar(PLT)
bl get_key(PLT)
mov r4, r0
mov r0, #66
bl putchar(PLT)
cmp r4, #3
cmpne r4, #1
movne r3, #0
moveq r3, #1
moveq r0, #0
beq .L19
.L4:
cmp r4, #2
bne .L6
mov r0, #1
.L19:
ldmfd sp, {r4, fp, sp, lr}
b show_freq_config(PLT)
.L6:
cmp r4, #4
beq .L20
cmn r4, #1
mov r0, r4
beq .L15
cmp r4, #0
beq .L20
bl putchar(PLT)
mov r0, #67
bl putchar(PLT)
b .L20
.L15:
mov r0, r3
ldmfd sp, {r4, fp, sp, pc}
.size show_system_info, .-show_system_info
.ident "GCC: (GNU) 3.4.6"
$ cat switch.s
.file "hello.c"
.text
.align 2
.global show_system_info
.type show_system_info, %function
show_system_info:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
mov ip, sp
stmfd sp!, {r4, fp, ip, lr, pc}
sub fp, ip, #4
.L18:
mov r0, #65
bl putchar(PLT)
bl get_key(PLT)
mov r4, r0
mov r0, #66
bl putchar(PLT)
mov r0, r4
add r4, r4, #1
cmp r4, #5
addls pc, pc, r4, asl #2
b .L12
.p2align 2
.L13:
b .L10
b .L18
b .L6
b .L7
b .L6
b .L18
.L6:
mov r0, #0
b .L17
.L7:
mov r0, #1
.L17:
ldmfd sp, {r4, fp, sp, lr}
b show_freq_config(PLT)
.L12:
bl putchar(PLT)
mov r0, #67
bl putchar(PLT)
b .L18
.L10:
mov r0, #0
ldmfd sp, {r4, fp, sp, pc}
.size show_system_info, .-show_system_info
.ident "GCC: (GNU) 3.4.6"
自己写了个get_key()代码调试了一下两种方法都没有问题啊,这段代码逻辑应该是没问题的