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

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

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

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

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

谢谢。

返回值传递给调用者的方式也是函数调用约定的一部分。 看到这里 。

例如,关于cdecl

许多C系统使用cdecl调用约定来实现x86体系结构。 在cdecl ,函数参数以从右到左的顺序被压入堆栈。 函数返回值在EAX寄存器中返回(浮点值除外,它在x87寄存器ST0中返回)。

 [...] 

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

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

澄清:

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

当然,有很多有效的理由可以在他自己的答案中回答Chris所说的函数指针,但我只是在谈论你不需要这样做的情况。

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

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

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

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

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