c -当堆栈变量被函数调用的结果初始化时,是否复制结构?



假设我将在函数中返回一个大结构体,如下所示:

#include <stdio.h>
// this is a large struct
struct my_struct {
int x[64];
int y[64];
int z[64];
};
struct my_struct get_my_struct_from_file(const char *filename) {
int tmp1, tmp2; // some tmp. variables
struct my_struct u;
// ... load values from filename ...
return u;
}
int main() {
struct my_struct res = get_my_struct_from_file("tmp.txt"); // <-- here
printf("x[0] = %dn", res.x[0]);
// ... print all values ...
}

here标记的地方,我是否必须假设这个大结构体被复制,或者编译器是否可能做一些事情来避免这种情况?

谢谢

…我是否必须假设这个大结构体被复制了…

不,当然你不必做这样的假设。没有人要求您做出这样的假设,采用该语句作为假设,而不是从已知信息(如编译器文档或对生成的汇编代码的检查)中得出它,这将是不明智的。

在您展示的特定代码中,很可能好的编译器会进行优化,使结构不被复制。(使用Apple Clang 11进行的测试证实了这一点。)但这可能是过于简化的代码。如果对get_my_struct_from_file的调用出现在与其定义分离的翻译单元中,编译器将不知道get_my_struct_from_file正在访问什么。如果目标对象(本例中的res)先前将其地址传递给其他翻译单元中的其他例程,则编译器无法知道其他例程没有将地址隐藏在某个地方并且get_my_struct_from_file没有使用它。因此,编译器必须将get_my_struct_from_file返回的结构和返回值被赋值的结构视为单独的;它不能合并它们以避免复制。

要确保编译器做你想做的事,只需告诉它你想让它做什么。编写代码,使函数将结果直接放入您想要放入的结构中:

void get_my_struct_from_file(struct my_struct *result, const char *filename)
{
…
}
...
get_my_struct_from_file(&res, "tmp.txt");

here标记的地方,我是否必须假设这个大结构体被复制,或者编译器是否可能做一些事情来避免这种情况?

在语义上,结构是从函数的局部变量复制到调用者的变量。它们是不同的对象,就像其他类型的对象一样,设置一个结构等于另一个结构需要从一个结构的表示复制到另一个结构的表示。

避免复制的唯一方法是编译器将局部变量视为调用者结构的别名,但这在一般情况下是错误的。这样的混叠可以很容易地产生与没有混叠时明显不同的行为。

在某些特定情况下,编译器确实可以避免复制,但如果你想确保不发生复制,那么你应该显式地设置所需的混叠:

void get_my_struct_from_file(const char *filename, struct my_struct *u) {
int tmp1, tmp2; // some tmp. variables
// ... load values from filename into *u
}
int main() {
struct my_struct res = { 0 };
get_my_struct_from_file("tmp.txt", &res);
printf("x[0] = %dn", res.x[0]);
// ... print all values ...
}

最新更新