【问题标题】:C: Return value via stack/register questionC:通过堆栈/寄存器问题返回值
【发布时间】:2011-07-18 23:27:05
【问题描述】:

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

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

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

还有一个问题:是否应该说我想要返回的大于寄存器的对象应该存储在堆中并通过指针返回以防止所有操作而不是堆栈操作?

谢谢。

【问题讨论】:

    标签: c function return-value calling-convention


    【解决方案1】:

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

    例如关于cdecl

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

    [...]
    

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

    如果您在堆上分配内存,堆栈操作将比所需的堆操作快得多,因此堆栈总是更快。 (在 C 中)您可能希望返回指向堆上某物的指针的唯一原因是因为它不适合堆栈。

    澄清:

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

    当然,正如 Chris 在他自己的回答中所说,从函数返回指针有很多正当理由,但我只是在谈论您不需要这样做的情况。

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

    【讨论】:

    • “你可能想要返回一个指向堆上的指针的唯一原因(在 C 中)是因为它不适合堆栈。”不是真的,但我还是给了你一个 +1。
    • @Chris:我想我在那里误解了我的意图。但是 +1 回馈给深思熟虑的答案和引导我改进我的 cmets。
    • 我不认为你的意思和它听起来完全一样。我只是想引起你的注意。
    • “堆栈操作将比堆操作快得多” - 这是为什么呢?
    • @flow2k 非常粗略:堆栈的组织方式使得可以非常快速地对其进行操作;您通过接受对其分配的内存的相对生命周期的限制来为此付出代价。堆不存在任何此类限制,但您通过接受更多记账成本来为此付出代价。
    【解决方案2】:

    还有一个问题:是否应该说我想要返回的大于寄存器的对象应该存储在堆中并通过指针返回以防止所有操作而不是堆栈操作?

    嗯,也许吧。老实说,选择“指针返回”或“值返回”可能比“我希望返回更快”更有理由做出选择。例如,对于大型对象,通过指针返回比通过堆栈返回更快,但这并没有考虑到在堆上分配对象比在堆栈上分配更多的时间。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-06
      • 2021-01-13
      • 2020-02-06
      • 2021-03-07
      • 1970-01-01
      • 2015-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多