Consider the following program:
struct foo baz(void)
{
struct foo arg;
arg.x = 1;
return arg;
}
Here you are returning a struct that was allocated in the stack, this will lead to undefined behaviour and a crash if you are lucky.
As explained above by alexanderbrevig and Ian.M and others, you are mistaken. It is perfectly normal, defined, acceptable ISO C code. However, I understand why one would think it leads to undefined behaviour.
I created a small example at
Compiler Explorer, for anyone interested in what the compiler actually generates (defaults to SysV ABI on x86-64, i.e. Linux on Intel/AMD 64-bit). You'll see that on this ABI, when optimizations are enabled, functions that work on structures with two
int members do not access stack at all.
If we expand the structure to include four
int members, the ABI rules change: see
here. Comparing the
ivec2d_add() and
ivec2d_add_alt() functions, where the latter takes the temporary structure returned as an additional parameter, we find that the compiler generates exactly the same code. In other words, it is the caller that allocates the temporary variable to store the structure at, not the callee (function). This means that by returning a structure, we do not return an instance in the callee scope; the compiler makes sure it exists in the caller scope.
In the C99 standard (it just happens to be the easiest
to refer to), section 6.7.5.3p1 limits function return values; it cannot be a function type (although a function pointer is perfectly acceptable) nor an array. There is no mention of structures. Similarly, in the chapters where structures or type promotions or type conversions are described (like in 6.9.1p10, which describes that when used as function parameters, array and function expressions are converted to pointers), there is no mention of structures being converted to pointers at all. Indeed, even in sections that discuss
lvalues (expressions that can be used on the left side of assignment operations), structures are treated just like scalar variable types (unless they contain
const members or variably-modified members or a final flexible array member).
Hopefully, you can either accept my word and experimental results as proof that returning a structure from a function is not equivalent to returning something that only exists in the callee scope (like say a pointer to a local variable, allocated on stack), or explore the C99 or later standards for yourself to see that there is nothing in the standards that would allow a C compiler to behave that way.
The reason many make the same mistake as pardo-bsso did, is that when using arrays, the similar pattern would indeed yield undefined behaviour. For example, the following is indeed undefined behaviour:
char *bad(void)
{
char buffer[24] = "Hello";
return buffer;
}
However, the following is completely acceptable:
struct buffer {
char data[24];
};
struct buffer foo(void)
{
struct buffer b = { .data = "Hello" };
return b;
}
struct buffer bar(void)
{
return (struct buffer){ .data = "Hi from me too" };
}
Although the struct variable is instantiated/created in the function, it is not converted to a pointer like an array would be. Thus, we are not returning an address or even referring to any address; we are returning the structure
by value. It is up to the compiler (and as I mentioned before, the details are agreed in whatever ABI is being used) to handle it correctly, but it has to handle it correctly to comply with the C standard –– remember, the C standard does not allow the compiler to treat a structure that contains an array like an array; a structure is a structure and is passed by value, not by reference, even if that structure contains one or more arrays.