主要就是一个人测试printf,形参明明是一个short型,他非要用long long这个型的指示符去读取,竟然没错,他觉得很不可思议。
通过底下的讨论,逐渐看明白了几件事情。
1. 可变参数的函数 (如scanf, printf ... ),他们在传递函数时,会做函数的类型提升,不够int大小的提升到int大小。
RoachRock大牛如下说:
☆─────────────────────────────────────☆
RoachCock (我的饭盒我的饭) 于 (Sun Nov 29 19:33:04 2009) 提到:
标准规定的,对于编长参数,小于 int 的整数类型一律提升成 int,
这个例子就是,传了一个 int(4 byte),作为 long long(8 byte) 来读取,
在 x86-32 下就会出错。在 x86-64 下,虽然也是传递了一个 int,因为
x86-86 的寄存器宽度是 8 字节,堆栈的单位也是 8 个字节,所以运行时
每个参数又实际占用了 8 个字节(高四个字节空着)。
http://msdn.microsoft.com/zh-cn/library/ms235286.aspx
www.x86-64.org/documentation/abi.pdf
这个例子就是,传了一个 int(4 byte),作为 long long(8 byte) 来读取,
在 x86-32 下就会出错。在 x86-64 下,虽然也是传递了一个 int,因为
x86-86 的寄存器宽度是 8 字节,堆栈的单位也是 8 个字节,所以运行时
每个参数又实际占用了 8 个字节(高四个字节空着)。
http://msdn.microsoft.com/zh-cn/library/ms235286.aspx
www.x86-64.org/documentation/abi.pdf
2. 对于整数参数的传递,优先使用寄存器,其次才是压到栈顶。
RoachRock大牛如下说:
☆─────────────────────────────────────☆
RoachCock (我的饭盒我的饭) 于 (Sun Nov 29 19:41:21 2009) 提到:
有函数原型的不需要提升。
x86 下,整数参数优先通过通用寄存器来传递,寄存器不够用才会用堆栈。
http://msdn.microsoft.com/zh-cn/library/9z1stfyw.aspx
VC 下,i 放在 RCX 寄存器中,占最低的两个高字节。
Linux x64 下也差不多:
http://www.x86-64.org/documentation/abi.pdf
3.2 Function Calling Sequence
这些参数本来是放在寄存器中,没地址的。
因为你要取地址,编译器只好分配几个局部变量,把参数从寄存器中拷贝过去。
你试试调整一下 printf 变量的顺序,或许发现地址没规律呢。
gcc -S 看一下就明白了。
☆─────────────────────────────────────☆x86 下,整数参数优先通过通用寄存器来传递,寄存器不够用才会用堆栈。
http://msdn.microsoft.com/zh-cn/library/9z1stfyw.aspx
VC 下,i 放在 RCX 寄存器中,占最低的两个高字节。
Linux x64 下也差不多:
http://www.x86-64.org/documentation/abi.pdf
3.2 Function Calling Sequence
这些参数本来是放在寄存器中,没地址的。
因为你要取地址,编译器只好分配几个局部变量,把参数从寄存器中拷贝过去。
你试试调整一下 printf 变量的顺序,或许发现地址没规律呢。
gcc -S 看一下就明白了。
Leimiaos (3WATER) 于 (Sun Nov 29 20:26:47 2009) 提到:
栈上不一定分配空间呀,寄存器不够或者递归才分配
对于小函数,寄存器传参可以很大程度上接近inline的效果,但是又不增加代码体积
需要开GCC的优化选项,这样就不会在栈分配空间,而直接通过寄存器传递参数。
☆─────────────────────────────────────☆
RoachCock (我的饭盒我的饭) 于 (Mon Nov 30 11:39:35 2009) 提到:
是的,x86-32 下,传递 short 的时候,如果没有函数原型,会符号扩展成 int 放进
堆栈,%lld 回去读取 8 个字节,多取到的是没有意义的。
没有评论:
发表评论