前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >请教关于C语言形参和实参存储单元的问题?

请教关于C语言形参和实参存储单元的问题?

原创
作者头像
用户8639654
修改2021-07-22 14:25:38
1.2K0
修改2021-07-22 14:25:38
举报
文章被收录于专栏:云计算运维

作者:灵剑 链接:https://www.zhihu.com/question/47514375/answer/106347643 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

首先我们限定一下问题,只限于cdecl的调用约定,函数没有被编译器做inline的优化(C++才有inline,但是C编译器也可能自己把函数调用优化掉)。除了cdecl以外,C中其他常用的调用约定包括stdcall和fastcall,C++中还有一个thiscall(用于调用类的成员函数)。fastcall会使用寄存器来传递一部分参数。stdcall除了返回时自动清理堆栈以外,与cdecl在使用参数上区别不大。thiscall调用约定使用寄存器传递this指针参数。pascal调用约定跟stdcall类似,但是参数入栈的顺序是反的。 在cdecl的调用约定下,所有参数从右往左入栈,都要占用存储空间。如果返回值大小超过eax范围,还要额外压一个返回值预留空间到堆栈里,然后从堆栈返回,否则从eax返回。从这个角度来说,所有的实参都必须要占用独立的空间。而且C语言也不支持传递引用作为参数。 纠结的在于传递数组作为参数这种情况,对编译器来说,实际上的参数是个指针,但是从代码形式上来看形参好像是个数组……这个我也不知道该怎么算,这简直是个哲学问题。如果从定义的角度上看,这时候参数类型是数组,那姑且算是你同学对吧,但是是有争议的。 不过,有另一个很好的理由可以选D:

如果传递的实参是个常量,这个常量并不会占用额外的空间。 比如说:

代码语言:javascript
复制
int f(int a);

int main(){
    f(1);
    return 0;
}

这个1,在实际运行的时候并不会有额外的空间来存储,而是直接从指令中压一个1到堆栈里然后直接调用。这个时候显然不是“实参和形参各占用独立的存储单元”。 传递一个固定的指针作为实参的时候也是一样的:

代码语言:javascript
复制
int f(int *a);

int main(){
    int r = 0;
    f(&r);
    return 0;
}

这个&r也不会有专门的存储单元去保存,而是直接通过bp + 固定偏移量的方式压进堆栈。

=======================================================================

感谢评论指出的问题,cdecl、stdcall、fastcall是x86中的调用约定,x64中已经不同了,查了一下相关的资料,在Windows上和非Windows上,使用的调用约定是有差异的。另外x86上gcc for linux和windows也是有差别的。 x86 calling conventions 可以参考wikipedia

简单来说,x64下Windows只有一种调用约定: 前四个整数(指针)参数按顺序使用RCX, RDX, R8, R9,前四个浮点参数按顺序使用XMM0, XMM1, XMM2, XMM3,剩余的参数从右往左进堆栈。另外,调用方在栈上额外分配32个字节(但是不需要初始化),给RCX、RDX、R8、R9四个参数,这样被调用的函数在需要使用这四个寄存器的时候可以把这四个参数直接存到堆栈里对应的位置上,腾出寄存器的空间。

gcc x64在Linux下则按照SystemV的调用约定: 前六个整数或指针类型使用RDI, RSI, RDX, RCX (Linux内核中使用R10),R8,R9浮点数使用XMM0,XMM1,XMM2,XMM3,XMM4,XMM5,XMM6和XMM7,没有额外的分配空间,剩余参数仍然是从右往左进栈。

使用寄存器传参数的时候,按照传统的占用存储的说法就不合适了,不过由于这些寄存器都是易失的,用于传参之后寄存器里原来的值必须先保存到堆栈上,也可以相当于占用了相应的存储空间,前面的讨论仍然是适用的。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档