出现随机的数字,我猜想可能是编译器编译以后进行代码优化时所造成的,我上面展开的汇编语句,并不是所有编译器都这么做的,我想如果这么看似简单的一个函数作为面试题,不会让你得出是一个随机值这么简单,这样的结果学了程序的人应该一眼都能看出来。
我想这个并不是一个很好的解释,希望有其他高手给点意见。
[此贴子已经被作者于2007-9-3 16:57:46编辑过]
我们都在命运湖上荡舟划桨,波浪起伏使我们无法逃离孤行;如果我们迷失方向,波浪将指引我们穿过另一天曙光
收回上面的话,这题目的确有意思,仔细想了想运行结果为0
由于switch()没有break语句一路运行到底。
比如func(1)时
运行30; 20; 16; 0;
仔细看看,这些语句并非无意义。
化成汇编语言来看。
30; => mov ax, 30d
20; => mov ax, 20d
16; => mov ax, 16d
0; => mov ax, 0d
最后ax中的结果是0
执行return b其实就是对应汇编语句如下:
mov (WORD PTR)b, ax
ret
注:BC3.1运行结果为0,并非不可预料的值。
mov (WORD PTR)b, ax
这句你是重c语言里那一句翻译过来的
汇编语言过程调用是怎样一个情况呢?
对于func有一个参数, 并且参数的类型为int,也就是2个字节(16位编译器中)
C语言中调用func,如下形式
func(1); // 值1传入参数
同样汇编语言中调用过程func,如下
mov ax, 1d
push ax
CALL func
在执行过程前,需要将参数压栈,执行了CALL func以后也就是间接执行了如下语句
push cs
pop ip
mov ax, SEG func
push ax
首先将当前代码段保存和指令寄存器,然后func所在的代码段压栈了,执行了CALL以后系统从堆栈中取出func所在的代码段,并充定向当前代码段:
pop cs
这样一来,开始的下一条指令cs:ip就从func内的第一条语句开始执行。
运行到这里堆栈内的情况是
[?][?][?][0x0001][ip][cs][?][?]...[?] (x86体系堆栈是从左往右增长的)
sp ss
当前栈顶指正指向cs那一块,也就是保存的原来调用点代码段的段地址,我们如何获得压栈以后的参数0x0001呢,很容易,如下语句可完成
push bp; 保存一下bp
mov bp, sp-4; x86的堆栈单元是2个字节为单位的
mov ax, WORD PTR [bp] ;取参数0x0001
pop bp
好了,参数有了,这样就可以运行程序了,当这个过程结束后必须返回到调用点,即ret语句,没有这个语句程序将顺序执行到一个不可预料的地步。(上述代码构建一个框架指针)
ret语句作的工作是
pop ip
pop cs
然后令ip = ip + 1 -> 这个应该是cpu做的工作,继续执行cs:ip的代码,也就是调用点之后的代码。
[此贴子已经被作者于2007-9-3 18:27:10编辑过]
呵呵
yuki兄很认真 写拉这么多
执行程序的下一条指令的确是cs:ip
但是我感觉这个和我问的没什么联系吧 。
我只是问return b;
这一句语句可以对应两句汇编,即
mov WORD PTR b, ax
ret ;
在汇编里 ax是一个寄存器, 他怎么会在最后把这个寄存器的值给b呢?
要给b那么在c里也该有b=?;
它既然没有这一句 , 那你又为什么在汇编里加一句mov WORD PTR b, ax呢
对,这个问题提得好,我刚想到。
这里是将b的执返回上去,也就是得把b的值传递给AX
mov ax, WORD PTR b ;由于b没有初始化也没有赋值,则返回的是一个不可预料的值。
但是,有些编译器结果为何是0。
有些编译器在生成目标代码的时候,发现b变量没有被引用,则返回b的值也就是相当于将经过最后一步操作的AX的值返回了(因为编译器认为b在这里并没有意义,也就是为什么许多编译器会警告b没有被引用)
感谢这位兄弟的问题启发了我。