函数调用中的堆栈分配

Con*_*mer 2 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;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,整型变量var1和的值var2被复制到函数参数a和 ,b并存储在为函数分配的堆栈帧中boo()。我的问题是:

如果我写

void boo (int a, int b) {}

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

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

是整数文字1并且2不存储在main()堆栈帧中,因为它们现在是右值?

如果我改为写

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

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

    boo(var1,var2);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

是参数a并且b仍然存储在函数的堆栈帧中boo()作为某种备份等。或者它们现在只是对实际参数的var1引用var2

for*_*818 5

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

你的代码:

void boo (int a, int b) {
}

int main() {

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

    boo(var1,var2);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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

int main() {}
Run Code Online (Sandbox Code Playgroud)

整数文字不得存储在任何地方。它们甚至不需要出现在可执行二进制文件中。对于代码中的其他代码示例也是如此。有关更多详细信息,请参阅“假设”规则到底是什么?以及C++ 中文字常量的存储


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

int main() {
    return [](int x){
        int sum = 0;
        for (int i=0;i<x;++i) sum += i;
        return sum;
    }(5);
}
Run Code Online (Sandbox Code Playgroud)

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

main:
        mov     eax, 10
        ret
Run Code Online (Sandbox Code Playgroud)

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

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

  • @ConventionalProgrammer,带有“/*一些代码*/”的注释,我会写这个答案没有什么不同。注释不是代码。我的观点是,编译器的输出取决于您遗漏的细节。 (2认同)