This is almost always about ABI stability. Binary stability between versions of the library. In the cases where it is not, it is sometimes about having dynamically sized structs. Rarely it is about extremely large struct
s or performance.
It is exceedingly rare that allocating a struct
on the heap and returning it is nearly as fast as returning it by-value. The struct
would have to be huge.
Really, speed is not the reason behind technique 2, return-by-pointer, instead of return-by-value.
Technique 2 exists for ABI stability. If you have a struct
and your next version of the library adds another 20 fields to it, consumers of your previous version of the library are binary compatible if they are handed pre-constructed pointers. The extra data beyond the end of the struct
they know about is something they don't have to know about.
If you return it on the stack, the caller is allocating the memory for it, and they must agree with you on how big it is. If your library updated since they last rebuilt, you are going to trash the stack.
Technique 2 also permits you to hide extra data both before and after the pointer you return (which versions appending data to the end of the struct is a variant of). You could end the structure with a variable sized array, or prepend the pointer with some extra data, or both.
If you want stack-allocated struct
s in a stable ABI, almost all functions that talk to the struct
need to be passed version information.
So
something_t make_something(unsigned library_version) { ... }
where library_version
is used by the library to determine what version of something_t
it is expected to return and it changes how much of the stack it manipulates. This isn't possible using standard C, but
void make_something(something_t* here) { ... }
is. In this case, something_t
might have a version
field as its first element (or a size field), and you would require that it be populated prior to calling make_something
.
Other library code taking a something_t
would then query the version
field to determine what version of something_t
they are working with.