函数调用中的堆栈分配

Stack allocation in a function call

提问人:ConventionalProgrammer 提问时间:3/15/2023 最后编辑:Benjamin BuchConventionalProgrammer 更新时间:3/15/2023 访问量:126

问:

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

void boo (int a, int b) {}

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

    boo(var1,var2);

    return 0;
}

在此方案中,整数变量的值被复制到函数参数中,并存储在为函数分配的堆栈帧中。我的问题是:var1var2abboo()

如果我写

void boo (int a, int b) {}

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

    return 0;
}

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

如果我改写

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

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

    boo(var1,var2);

    return 0;
}

是参数,并且仍然存储在函数的堆栈帧中作为某种备份等。还是它们只是对实际参数的引用?abboo()var1var2

C++ 按引用 传递值

评论

0赞 blackgreen 3/15/2023
评论已移至聊天室;请不要在此处继续讨论。在下方发表评论之前,请查看评论的目的。不要求澄清或提出改进建议的评论通常属于 Meta Stack Overflow 或 Stack Overflow Chat 中的答案。继续讨论的评论可能会被删除。

答:

5赞 463035818_is_not_an_ai 3/15/2023 #1

您编写的代码不是针对 cpu 的指令。它是编译器的说明。读完这个答案后,你可能会争辩说你的代码只是一个简化的例子,但和你的编译器一样,我只能使用你提供的东西。编译器将代码转换为计算机指令,这些指令具有 c++ 标准中为代码指定的可观察行为。

您的代码:

void boo (int a, int b) {
}

int main() {

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

    boo(var1,var2);

    return 0;
}

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

int main() {}

整数文本不得存储在任何地方。它们甚至不需要出现在可执行二进制文件中。代码中的其他代码示例也是如此。有关更多详细信息,我建议您参考“假设”规则到底是什么? 以及 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

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

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

评论

0赞 ConventionalProgrammer 3/15/2023
哦。。。我认为@273K的编辑造成了混乱。我首先写了/这里有一些代码/代码中的注释。换句话说,我假设有隐式操作,如 int c {};c=a*b;等。 在函数的主体中
2赞 463035818_is_not_an_ai 3/15/2023
@ConventionalProgrammer有类似的评论,我会写这个答案,没有什么不同。注释不是代码。我的观点是,编译器的输出取决于您遗漏的细节。/* some code */
0赞 463035818_is_not_an_ai 3/15/2023
@ConventionalProgrammer考虑这个例子 godbolt.org/z/n6jWh411K。2 个整数文本,1 个传递给函数。在编译器的输出中,甚至没有剩余的函数调用。不保证优化。更改微小的细节或编译器标志可以完全更改编译器的输出,但行为将始终相同:它返回 10
1赞 463035818_is_not_an_ai 3/15/2023
...这才是最重要的。该代码是运行时行为的抽象描述。当你用 main 编写并将返回 10 时,那么只要程序从 main 返回 10,那么 5 存储在哪里并不重要return foo(5);foo(5)
0赞 ConventionalProgrammer 3/15/2023
感谢您的解释性回答。