user541686
user541686

Reputation: 210445

Why doesn't C code return a struct?

While it's very handy, I very rarely, if ever, come across functions that return structs (or unions) in C, whether they are dynamically linked functions or statically defined functions.
They instead return the data through a pointer parameter.

(An dynamic example in Windows is GetSystemInfo.)

What's the reason behind this?
Is it because of a performance issue, an ABI compatibility issue, or something else?

Upvotes: 21

Views: 10425

Answers (7)

Dave
Dave

Reputation: 11162

The reasons are mostly historical. In his paper, "The Text Editor sam", Rob Pike writes

A related matter of programming style: sam frequently passes structures by value, which simplifies the code. Traditionally, C programs have passed structures by reference, but implicit allocation on the stack is easier to use. Structure passing is a relatively new feature of C (it is not in the standard reference manual for C14), and is poorly supported in most commercial C compilers. It’s convenient and expressive, though, and simplifies memory management by avoiding the allocator altogether and eliminating pointer aliases.

That being said, there are pitfalls to the technique; returning obscenely large structures chances stack overflow.

Upvotes: 8

A C function can return a structure (and so does a C++ one, where it is quite common). Perhaps in the very first years of C, it could not.

The x86-64 ABI specification for Linux and related systems (page 21) even says that structures fitting into two -64 bits- words can often be returned in two registers without going thru the memory (even the stack). Very probably this is faster than going thru the stack.

As unwind replied in his answer, the ABI often requires structure results to be silently converted to an invisible pointer.

One could even define another calling convention which returns more data in more registers. But such new conventions would break all object code and require recompilation of everything (including even, on Linux, system libraries like libc.so.6), and of course require changing the compiler.

Of course, ABI conventions are processor, system and compiler related.

I don't know Windows and I don't know what Windows define as its ABI.

Upvotes: 6

Cédric Julien
Cédric Julien

Reputation: 80761

Returns in C are made by storing the return value in the stack.
Returning a struct or an union would lead to put potentially very big data on the stack, and this could lead to a stack overflow.

Returning only a pointer to the struct/union is pretty much safier because you only put a little quantity of data (4 bytes in general) in the stack.

Upvotes: 7

Michael Burr
Michael Burr

Reputation: 340208

In addition to the idea that there might be a performance hit or that returning structs by value might not have been commonly supported in pre-standard days another reason for C functions to not use return-by-value for structs is that if you return a struct you can't easily return a success/failure indicator. I know that I occasionally would start out designing a function to return a struct that was initialized in the function, but then I'd run into the problem of how to indicate whether or not the function succeeded. You pretty much have the following options:

  • guarantee success (sometimes this is possible)
  • pass in a pointer to a location for the error code
  • have a field or sentinel value in the struct that indicates success/failure

Only option 1 keeps the interface from being a kludge. The second option kind of defeats the purpose of returning the struct by value, and actually makes the function more difficult to use for handling failures. The third option is just plainly not a good design in nearly all cases.

Upvotes: 4

ouah
ouah

Reputation: 145829

In pre-ANSI C, you couldn't return object of structure type and you could also not pass arguments of structure types.

From Chris Torek quote in comp.lang.c:

Note that V6 C also did not support struct-valued arguments and struct-valued return values.

The reason nowadays they are not very used is people prefer to return pointer to structure which involves only a pointer copy instead of the copy of a whole structure object.

Upvotes: 4

Luchian Grigore
Luchian Grigore

Reputation: 258598

In general, Windows functions either return nothing or error codes, especially when it comes to returning structures or classes.

Efficiency might be an issue, although RVO should remove the overhead.

I think the main reason was to keep the methods inline with the coding style used before.

Upvotes: 0

unwind
unwind

Reputation: 399813

I would say "performance", plus the fact that it's even possible sometimes seems to surprise C programmers. It's not ... in the general "flavor" of C, to many, to throw around large things such as structs as if they were mere values. Which, according to the language, they really are.

Along the same lines, many C programmers seem to automatically resort to memcpy() when the need to copy structs arises, rather than just using assignment, too.

In C++ at least, there is something called "return value optimization" which is able to silently transform code like this:

struct Point { int x, y; };

struct Point point_new(int x, int y)
{
  struct Point p;
  p.x = x;
  p.y = y;
  return p;
}

into:

void point_new(struct Point *return_value, int x, int y)
{
  struct Point p;
  p.x = x;
  p.y = y;
  *return_value = p;
}

which does away with the (potentially stack-hungry) "true" return of a struct value. I guess even better would be this, not sure if they're that smart:

void point_new(struct Point *return_value, int x, int y)
{
  return_value->x = x;
  return_value->y = y;
}

I'm not sure if C compilers can do any of this, if they can't then I guess that might be a real argument against struct returns, for very performance-critical programs.

Upvotes: 13

Related Questions