c++ - 函数调用中的堆栈分配

标签 c++ pass-by-reference pass-by-value

当您调用函数时,如果传递给函数的参数不是数组,或者不是有意使用与号 (&) 符号按引用传递,则这些参数将按值传递。例如,

void boo (int a, int b) {}

int main() {
    int var1 {1};
    int var2 {2};

    boo(var1,var2);

    return 0;
}

在此场景中,整型变量 var1var2 的值被复制到函数参数 ab 并存储在为 boo() 函数分配的堆栈帧中。我的问题是:

如果我写

void boo (int a, int b) {}

int main() {
    boo(1,2);

    return 0;
}

整数文字12是否未存储在main()堆栈帧中,因为它们现在是右值?

如果我改为写

void boo (int &a, int &b) {}

int main() {
    int var1{1};
    int var2{2};

    boo(var1,var2);

    return 0;
}

参数ab仍然作为某种后台存储在boo()函数的堆栈帧中吗?或者它们现在只是对实际参数 var1var2 的引用?

最佳答案

您编写的代码不是针对您的CPU的指令。它是针对您的编译器的说明。阅读此答案后,您可能会说您的代码只是一个简化的示例,但与您的编译器相同,我只能使用您提供的内容。编译器将您的代码转换为机器指令,这些指令具有 C++ 标准中为您的代码指定的可观察行为。

您的代码:

void boo (int a, int b) {
}

int main() {

    int var1 {1};
    int var2 {2};

    boo(var1,var2);

    return 0;
}

与此具有完全相同的可观察行为:

int main() {}

整数文字不得存储在任何地方。它们甚至不需要出现在可执行二进制文件中。对于代码中的其他代码示例也是如此。欲了解更多详情,请参阅What exactly is the "as-if" rule?Storage of literal constants in c++ .


为了便于说明,请考虑一个不同的示例:

int main() {
    return [](int x){
        int sum = 0;
        for (int i=0;i<x;++i) sum += i;
        return sum;
    }(5);
}

我希望它足以证明打开优化的 gcc 会产生以下输出,而不是在语言律师的基础上讨论它:

main:
        mov     eax, 10
        ret

文字5没有存储在任何地方。如果您愿意,可以尝试将 int x = 5; 传递给 lambda,这不会产生任何影响。正如 PaulMcKenzie 在评论中提到的,您可以将带有循环的 lambda 转换为递归函数,您仍然会看到相同的效果:任何地方都没有 5

Gcc 正确地认识到上述代码的可观察行为是(用简单的英语术语):“从 main 返回 10”,因此它产生了执行此操作的输出。现在你问“5 存储在哪里?”但该代码只是描述从 main 返回 10 的复杂方式,并且不需要在任何地方存储 5

关于c++ - 函数调用中的堆栈分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75736567/

相关文章:

c++ - 静态存储持续时间对象的破坏和未定义的行为

java - 如何使用 C++ 读取用 Java (writeObject) 保存的文件

c# - 检查引用参数值或返回 bool 值?

Python 通过引用 DLL 传递用户定义的类

java - C++ 中传递的函数参数与 Java 中传递的函数参数

c++ - 对 Winsock DEFAULT_PORT 的 PCSTR 的 Int

c++ - 将 reinterpret_cast 转换为可变大小的数组

C++:为什么对于内置(即类 C)类型,按值传递通常比按引用传递更有效

Delphi:实际参数和形式参数的类型必须相同

java - 我们可以在java中使用引用传递吗?如果否,java.util.Arrays.sort 是如何工作的?