我不是一名C程序员,但我最近对此感兴趣。据我所知,在C函数中,参数是通过值传递的,这就解释了为什么v1没有改变。
我不明白的是为什么v2在stack_copy返回后具有正确的值。我的理解是函数args被放在堆栈上,应该在函数范围的末尾进行处理,所以我希望v2包含垃圾。
这里发生了什么?
注意:我在Windows上使用Visual Studio 2015编译器在OS上进行了测试,并在OSX上进行了操作。
#include "assert.h"
typedef struct {
int x;
int y;
int z;
} Vec3;
Vec3 stack_copy(Vec3 v) {
v.x = 3;
v.y = 3;
v.z = 3;
return v;
}
int main() {
Vec3 v1 = {7, 7, 7 };
Vec3 v2 = stack_copy(v1);
assert(v1.x == 7 && v1.y == 7 && v1.z == 7);
assert(v2.x == 3 && v2.y == 3 && v2.z == 3);
return 0;
}
答案 0 :(得分:2)
我假设你知道C中“按值调用”的概念,即你不是在询问参数似乎是一个参考(C ++风格)。
否则,她就主题Parameter Passing in C - Pointers, Addresses, Aliases
你对这个问题的关注点是返回结构类型的值 同样的事情发生在“出路”上,即将值复制回函数的返回值被分配给的任何内容。
结构类型值与其他任何值都没有区别。
我认为在查看此示例时您没有想到您的问题:
int stack_copy(int v) {
v = 3;
return v;
}
答案 1 :(得分:1)
您按值传递值就像通过值一样。当然,参数v
被释放(至少在语义上是因为编译器可以使用RVO返回值优化来优化它),但是它的值被返回并复制到v2
中。定义类型定义其可能的值,对于结构,它是元素类型的笛卡尔积。因此,返回Vec3
只会返回三个整数的 pack 。
答案 2 :(得分:0)
你是对的,局部变量在堆栈上分配。
调用方法时,会将v1的副本推入堆栈,并且以下所有操作都会更改该确切对象。
但是,编译器还执行了一个额外的步骤来允许非原始返回值(结构):在调用方法时,会传递一个额外的指针。它指向来自调用者堆栈的地址,并且返回值直接写入该地址。这也可以防止其他副本,并被称为"返回值优化"。