C:通过堆栈/寄存器问题返回值

时间:2011-03-20 01:18:49

标签: c function return-value calling-convention

我是C的新手,有一件事我无法理解。 当函数返回不大于寄存器的东西时 - 我的编译器把它放在EAX中。 当我返回大结构(不是指针而是结构本身)时 - 它通过堆栈返回。

我的问题是:编译器如何知道如何调用另一个对象导出的函数? 有一个调用约定(比如stdcall)但它是关于传递参数,而不是读取返回的值,对吗?

应该有一些规则,例如“如果声明的返回值大于EAX,则从[bp -...]获取”。

还有一个:说我想要返回的对象(比寄存器大)应该存储在堆中并由指针返回以防止所有堆栈操作,这是正确的吗?

感谢。

2 个答案:

答案 0 :(得分:18)

返回值传递给调用者的方式也是函数调用约定的一部分。请参阅here

例如,关于cdecl

  

使用cdecl调用约定   许多C系统为x86   建筑。在cdecl中,功能   参数被压入堆栈中   从右到左的顺序。功能返回   值在EAX中返回   寄存器(浮点除外)   值,在x87中返回   注册ST0)。

[...]
  

有一些变化   cdecl的解释,特别是   在如何返回值。结果是,   x86程序编译为不同的   操作系统平台和/或   不同的编译器可以   不兼容,即使他们都使用   cdecl约定,不要打电话   到底层环境。   一些编译器返回简单数据   结构长度为2   在EAX中注册或更少:EDX,和   更大的结构和类对象   需要特殊待遇   异常处理程序(例如,已定义的   构造函数,析构函数或   赋值)在内存中返回。至   传递“在内存中”,调用者分配   内存并将指针传递给它   隐藏第一个参数;被叫者   填充内存并返回   指针,弹出隐藏的指针   回来时。

如果在堆上分配内存,堆栈操作将比必要的堆操作快得多,因此堆栈总是更快。唯一的原因(在C中)你可能想要返回指向堆上某些东西的指针是因为它不适合堆栈。

<强>澄清:

在上面的最后一句中,“你可能想要的唯一理由......”不应被解释为“通常没有理由返回指针”。相反,我的意思是“如果你可以在不返回指针的情况下做你需要的东西,那么决定使用指针的唯一理由就是......”。

当然,有很多正当理由可以回答Chris在其自己的答案中指出函数的指针,但我只是在谈论你不需要 这样做的情况。 / p>

换句话说,尽可能按价值返回;必须时使用指针。

答案 1 :(得分:4)

  

还有一个:说我想要返回的对象(比寄存器大)应该存储在堆中并由指针返回以防止所有堆栈操作,这是正确的吗?

好吧,也许吧。老实说,“按指针返回”或“按价值返回”的选择是你应该有更好的理由而不是“我希望回报更快”。例如,对于大型对象,通过指针返回比通过堆栈更快,但这并没有考虑到与堆栈相比在堆上分配对象所花费的时间更长。

更重要的是,返回指针允许您拥有不透明指针,可变大小的对象以及堆栈对象中不可能的某种程度的多态行为。如果你想要或需要这些行为,你应该使用return-by-pointer。如果不这样做,您可以使用按值返回,或者您可以将指针传递给用户分配的对象(但是他们喜欢)作为参数并在函数中修改该参数(这有时称为“ out参数“或类似的东西。”

根据您的需要和代码的作用选择返回方法,而不是您认为更快的方法。如果你发现你绝对需要速度(在分析并发现返回是一个瓶颈之后),然后担心这种微优化。