C: Return value via stack/register question

Ilya picture Ilya · Mar 20, 2011 · Viewed 10.2k times · Source

I am new to C, and there is one thing I can not understand. When function returns something that is not bigger than register -- my compiler puts it in EAX. When I return big structure (not pointer but structure itself) -- it is returned via stack.

My question is: how compiler knows how to call function exported by another object? There is a calling conventions (like stdcall) but it is about passing the arguments, not reading the returned value, right?

There should be some rule like "If return value declared to be larger than EAX, than take it from [bp-...]".

And one more: would it be right to say that objects I want to return, larger than register should be stored in heap and returned by pointer to prevent all than stack manipulations?

Thanks.

Answer

Jon picture Jon · Mar 20, 2011

The way that the return value is passed to the caller is part of the function calling conventions as well. See here.

For example, regarding cdecl:

The cdecl calling convention is used by many C systems for the x86 architecture. In cdecl, function parameters are pushed on the stack in a right-to-left order. Function return values are returned in the EAX register (except for floating point values, which are returned in the x87 register ST0).

[...]

There are some variations in the interpretation of cdecl, particularly in how to return values. As a result, x86 programs compiled for different operating system platforms and/or by different compilers can be incompatible, even if they both use the cdecl convention and do not call out to the underlying environment. Some compilers return simple data structures with the length of 2 registers or less in EAX:EDX, and larger structures and class objects requiring special treatment by the exception handler (e.g., a defined constructor, destructor, or assignment) are returned in memory. To pass "in memory", the caller allocates memory and passes a pointer to it as a hidden first parameter; the callee populates the memory and returns the pointer, popping the hidden pointer when returning.

The stack manipulations are going to be much much faster than the heap manipulations necessary if you allocate memory on the heap, so stack is always faster. The only reason (in C) you might want to return a pointer to something on the heap is because it won't fit on the stack.

Clarification:

In the last sentence above, "the only reason you might want..." should not be interpreted as "there is normally no reason to return a pointer". Rather, I mean "if you can do what you need without returning a pointer, the only reason to decide to use a pointer anyway is...".

Of course there are many valid reasons to return pointers from functions as Chris states in his own answer, but I 'm only talking about the cases where you don't need to do so.

In other words, return by value when you can; use pointers when you must.