【问题标题】:Are function arguments guaranteed to pass on the stack?函数参数是否保证在堆栈上传递?
【发布时间】:2014-11-26 19:37:12
【问题描述】:

假设函数参数将在堆栈上按顺序传递是否安全?

例如,无论编译器设置如何,foo 是否保证输出x y z

void foo(int x, int y, int z) {
    int *vector = &x;
    for(int i = 0; i < 3; i++) {
        std::cout << vector[i] << " ";
    }
}

我在 Visual Studio 中尝试过,它确实有效,但我不确定这种行为是否得到保证。

【问题讨论】:

  • 输出:1137301924432767,简短回答:NO
  • 不,理论上这是未定义的行为。在实践中,calling conventions 确定参数的传递方式,并且在不同平台上可能有所不同(跨 API 调用时,编译器在自包含编译单元内执行的操作可能与 call-to-call 不同)。
  • @πάνταῥεῖ 关闭这个不是一个真正的问题!哦等等……
  • 此外,即使您可以通过这种方式以明确定义的方式读取堆栈,也不在许多真实计算机上打印x y zyz 可能位于 vector[-1]vector[-2](取决于堆栈增长的方向),或者参数可能在寄存器中传递(将 x 复制到堆栈以使其具有地址) .
  • 当我尝试它时这对我有用,我想知道这是否总是如此,以及这是否是一个安全的假设。我不明白这怎么跑题了。

标签: c++ language-lawyer undefined-behavior


【解决方案1】:

无论编译器设置如何,您的程序都有未定义的行为

您可以将&amp;x 视为一个 int 数组的第一个元素的地址,因此vector[1]vector[2] 是越界数组访问。

【讨论】:

    【解决方案2】:

    该语言做出此保证。参数通常在堆栈上和寄存器中传递,或者两者的组合。这取决于 ABI 和调用约定。

    【讨论】:

      【解决方案3】:

      简短回答:不。

      长答案 - 每种处理器类型都有一组或多组与之关联的调用约定。这决定了参数通常如何传递——通常是在寄存器和堆栈位置的某种组合中。如果一个聪明的编译器/优化器知道一些关于上下文的东西,它可以在特定的实例中覆盖这些约定,甚至包括根本不传递(未使用的等)参数。 (这让实现调试工具的人很痛苦 ;-()

      为了让事情更具体 - 普通英特尔处理器的约定根据它们是在 32 位还是 64 位模式下运行而有所不同。

      【讨论】:

      • 相信你错了,调用约定是编译器决定的。
      • @HugoBurd 他这么说the compiler can override those conventions in specific instances。但从根本上说,平台定义了一个调用约定,如果编译器想要与该平台上的其他库链接,它必须符合该平台上的调用约定(用于调用系统库和将回调传递给它们)。当然,在将 ABI 跨入系统或其他库之前,您可以在内部执行您想要的调用约定,但使用系统 ABI 的优势在于也能够创建库(对于所有遵守 ABI 的编译器)。
      • 啊,我错过了那部分。感谢您的澄清。
      • IIRC,我见过在同一硬件上支持多个竞争约定的实例,具体取决于特定操作系统(和相关工具链)之类的东西。
      • @ArlieStephens 是的,这就是我写“平台”而不是像你那样写处理器的原因。你甚至可以在内核空间和用户空间有不同的调用约定(我相信 PS3 就是这种情况)
      【解决方案4】:

      换句话说,这样写是一个错误

      (还有一个非常糟糕的!)

      这是第一条规则,恕我直言:“说出你的意思。” 不要试图变得聪明、高效或可爱。不要假设任何关于实施的事情;不要试图为它做优化编译器的工作。为你的同事(以及你未来的自己)写更多的东西,而不是为电脑写的。此外,努力使您的代码可维护。“面向未来”。

      如果这意味着,比如说,“冗余”、“低效”、“不雅”,写“额外”语句来做一些可以“打高尔夫球”成更少语句的事情,“鲸鱼在乎谁?”(我们现在正在使用每秒可以执行 十亿 次操作的硬件。)人们唯一关心的是您的代码何时不起作用或何时破坏其他东西.

      简单 ... human(!) ... 清晰 ... 是 ... 关键。 写清楚,就不会出错。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-30
        相关资源
        最近更新 更多