structure function returns -- how?
Stuart D. Gathman
stuart at bms-at.UUCP
Wed Dec 24 12:53:05 AEST 1986
In article <490 at aw.sei.cmu.edu.sei.cmu.edu>, firth at sei.cmu.edu (Robert Firth) writes:
[ we are discussing returning structures from functions ]
> (a) Registers. If the structured object is small enough, use the
Definitely do this is all cases.
> (b) Caller preallocates. This passes as an extra parameter a pointer
> to a result area computed by the caller. Note that this requires
In most cases this will be object being assigned to. Only
when the selection operator is applied to the function result
will a temp area have to be allocated. See ultimate solution
below.
> (c) Function allocates static space and returns pointer. Caller copies.
I hate this because it is inefficient; the structure is copied
twice! Unfortunately all of the compilers we have do it because
it is simple for the compiler. However, some of the objections
below do not hold water.
> This is not reentrant, as has been pointed out. Nor does it work if
> the function is recursive. Since reentrancy bugs are very hard to
> find, as a compiler writer I would absolutely NEVER use this technique.
It *is* recursive (the static area is only used by the return
statement - think about it). It is also reentrant if each process
has its own static area as it should anyway for anything reasonable
to happen. (This is where the const storage class comes in
handy. Constants can be shared. Shared data has to be accessed
via pointers or else declared via a non-ansi global storage class.)
This method has problems when the function is called from a signal
catching function.
> A variation is for the function to return a pointer to a declared
> object holding the value. For example, if the function does a lookup
> of an external array of struct objects, it can simply return a pointer
> into the table.
In fact, it can return a pointer to any class of variable
including auto - except that signals will bomb when auto is
handled in this way. It is
still recursive and reentrant though and eliminates the
double copy. This works because the function result is
an rvalue and can be assigned or passed on the stack without
wiping its value on most architectures.
> (d) Allocate on heap
Boooooo! Hisss. You might as well not allow functions
returning structures; it is that inefficient.
> (e) Function leaves result on stack.
This works best when done a la pascal. The caller decrements
the stack pointer (for descending stacks) to reserve room
for the result before stacking function arguments. The
function does the copy. Another copy is required if doing
an assignment, but passing the result to another function
requires no extra overhead! (Not even the code in the calling
sequence to do the copy.)
Knowledge of the structure size is required at compile time.
This is re* and immune to interrupts. It also works with
signals.
*** The real solution ***
(f) For an assignment, the caller passes a pointer to the object
being assigned. The function does the copy.
For a function argument (including selection), the stack
pointer is decremented as in (e) and a pointer to the
stack area so reserved is passed. (I.e. save the stack pointer
in a register, decrement the stack pointer, push the register.)
Again, the function does the copy.
This is recursive, reentrant (even without seperate static areas),
immune to interrupts, works with signals, the result is
always copied only once, and the code for the copy is in
the function - not the calling sequence!
(I hate it when the result is copied twice! Grrr.)
P.S. This idea is free provided that the user implements it
on our compilers or else hires me to implement it on their compiler. :-)
--
Stuart D. Gathman <..!seismo!dgis!bms-at!stuart>
More information about the Comp.lang.c
mailing list