Given I'll return a large struct in a function like here:
#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] = %d\n", res.x[0]);
// ... print all values ...
}
At the place marked by here
, do I have to assume that this large struct is copied or is it likely that the compiler does something to avoid this?
Thank you
CodePudding user response:
… do I have to assume that this large struct is copied…
No, of course you do not have to make that assumption. Nobody requires you to make that assumption, and it would be unwise to adopt the statement as an assumption rather than deriving it from known information, such as compiler documentation or inspection of the generated assembly code.
In the specific code you show, it is likely good compilers will optimize so that the structure is not copied. (Testing with Apple Clang 11 confirms it does this optimization.) But that is likely overly simplified code. If a call to get_my_struct_from_file
appears in a translation unit separate from its definition, the compiler will not know what get_my_struct_from_file
is accessing. If the destination object, res
in this example, has had its address previously passed to some other routine in some other translation unit, then the compiler cannot know that other routine did not stash the address somewhere and that get_my_struct_from_file
is not using it. So the compiler would have to treat the structure returned by get_my_struct_from_file
and the structure the return value is being assigned to as separate; it could not coalesce them to avoid the copy.
To ensure the compiler does what you want, simply tell it what you want it to do. Write the code so that the function puts the results directly in the structure you want to put it in:
void get_my_struct_from_file(struct my_struct *result, const char *filename)
{
…
}
...
get_my_struct_from_file(&res, "tmp.txt");
CodePudding user response:
At the place marked by
here
, do I have to assume that this large struct is copied or is it likely that the compiler does something to avoid this?
Semantically, the structure is copied from the function's local variable to the caller's variable. These are distinct objects, and just like objects of other types, setting one structure equal to another requires copying from the representation of one to the representation of the other.
The only way to avoid a copy would be for the compiler to treat the local variable as an alias for the caller's structure, but that would be wrong in the general case. Such aliasing can easily produce observably different behavior than would occur without.
It is possible that in some specific cases, the compiler can indeed avoid the copy, but if you want to ensure that no copying happens then you should set up the wanted aliasing explicitly:
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] = %d\n", res.x[0]);
// ... print all values ...
}