Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!vrdxhq!dgis!bms-at!stuart From: stuart@bms-at.UUCP (Stuart D. Gathman) Newsgroups: comp.lang.c Subject: Re: structure function returns -- how? Message-ID: <326@bms-at.UUCP> Date: Tue, 23-Dec-86 21:53:05 EST Article-I.D.: bms-at.326 Posted: Tue Dec 23 21:53:05 1986 Date-Received: Wed, 24-Dec-86 03:41:44 EST References: <131@hcx1.UUCP> <773@maynard.BSW.COM> <7403@utzoo.UUCP> <490@aw.sei.cmu.edu.sei.cmu.edu> Organization: Business Management Systems, Inc., Fairfax, VA Lines: 90 Summary: The REAL solution (at end of article). In article <490@aw.sei.cmu.edu.sei.cmu.edu>, firth@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>