(接上文)
对于printf(“%f”, 10/3, 0×40080000);能输出3.000000的结果,根据前面几篇文章的内容稍作分析不难得出:
能输出这个结果,其实和printf的第二个参数10/3一点关系也没有,改为:printf(“%f”, 0, 0×40080000);也能输出这个结果。
这里利用不定参数表构造出了一个值:0×4008000000000000(如果第二个参数为3,那么就是0×4008000000000003),这个值就是双精度的3.0在内存中的存储形式。
当printf解析第一个参数格式化字符串后,以double方式来处理传入的参数,也就是请求一个8字节的数据,当前堆栈状态如下:
栈顶
————————————-
格式化字符串地址
可变参数起始地址–> ————————————-
不定参数第一个参数值0×00000000
————————————-
不定参数第二个参数值0×40080000
看起来我们多传递了一个参数,实际上这个参数被正确的用到了。在请求8字节的数据后,得到的值为:0×4008000000000000,显示出来就是3.000000
可以用上一篇文章写的sumfunf函数来验证一下:sumfunf(1, 0×00000000, 0×40080000);
程序按32bit方式编译的情况下,printf(“%f”, 0, 0×40080000);与printf(“%f”, 0×4008000000000000);等价。
大家知道,C/C++中的参数传递主要是通过堆栈进行,对于printf这样的函数来说,可变参数部分多一个、少一个参数编译器都不会给出任何提示,甚至只存在格式化字符串一个参数(如:printf(“%f”);),也能编译通过执行。
以调用sumfunf(1, 0×00000000, 0×40080000) 为例,编译后,代码被翻译为类似这样(示意):
push 40080000h
push 0
push 1
call _sumfunf
add esp,0Ch
稍微解释一下:push是将一个值压入堆栈,值在栈顶处压入,压入后栈顶上移一个字长,esp保存的是当前栈顶地址。
栈顶(esp指向)
———————————–
…已存在于堆栈的数据
执行push 40080000h 压栈后:
栈顶(esp指向)
———————————–
0×40080000
———————————–
…已存在于堆栈的数据
执行push 0压栈后:
栈顶(esp指向)
———————————–
0×00000000
———————————–
0×40080000
———————————–
…已存在于堆栈的数据
执行push 1压栈后:
栈顶(esp指向)
———————————–
0×00000001
———————————–
0×00000000
———————————–
0×40080000
———————————–
…已存在于堆栈的数据
在函数里面取参数的时候,也使用这个约定,按顺序从调用时的栈顶开始取值,第一个参数,第二个参数,第三个参数…
当函数调用完成后,需要进行退栈,于是将esp加上0ch(十进制12),压入了3个数据,每个数据占用4字节,总占用12字节,所以退栈的时候需要加12字节。
退栈后,栈顶又恢复了初始的值:
0×00000001
———————————–
0×00000000
———————————–
0×40080000
退栈后栈顶(esp指向)—> ———————————–
…已存在于堆栈的数据
试试用hack一点的手法来调用函数sumfunf(1, 0, 0×40080000),等价于:
_asm {
push 40080000h
push 0
}
float r = sumfunf(1); // 为了绕过语法检查,给出第一个参数
_asm add esp,08h
实际上,程序被编译为32bit的机器码执行,即是是写成sumfunf(1, 0×4008000000000000)这样的形式,编译器也处理为在入栈时拆分为2个字长进行处理。push默认是使用机器字长进行处理,如果机器字长是32bit,则是4个字节,每压栈一个数据栈顶指针减4;如果是16bit机器字长,栈顶指针减2,同理,如果是64bit,栈顶指针则减去8。所以可以知道如果按64bit字长编译的情况下,sumfunf(1, 0×00000000, 0×40080000)就不能输出原本期望的3.000000了。
讨论参数堆栈传递机制的背景知识,是为了引出这样一个问题:
按照这种说法,在32bit机器字长的情况下,为什么printf(“%f”, 3.0f);能输出期望的3.000000?sizeof(3.0f) 也等于4字节,如果说%f代表着期望获得一个8字节的double类型数据,那么还有4字节的数据呢,为什么不会为一个不确定的值?
(未完待续)