m100-2ai@WEB.berkeley.edu (05/29/90)
Hi everyone. The following seems to be an "easy" question. However, after thinking about it, I find that I don't really understand how it really works... Assume I have the following structure defined... typedef struct STRUCT STRUCT; struct STRUCT { int num; /* Other fields */ }; in ANSI C, I can define a function returning STRUCT, such as the following: STRUCT function(void) { STRUCT structure; structure.num = 0; /* Set other fields as well */ return structure; } Now, it seems that the storage space for 'structure' has to be allocated on the heap (not on stack). However, wouldn't this create a lot of garbages you won't be able to free? For example: boolean is_something(STRUCT s) { return s.num * ....; } And the call: if (is_something(function())) { printf("true."); } will create garbage because the we cannot access the 'structure' returned by function, and since it is allocated on the heap, it won't go away. Essentially, it is garbage. However, what strikes me more is that there seems to be no way you can free that garbage. I can try to do the following: STRUCT *ptr; ptr = &(function()); /* This may, or may not work, depending on */ /* your compiler. */ if (is_something(*ptr)) { printf("true."); } free(ptr); /* Again, may or may not work. */ As a matter of fact, there seems to be NO WAY you can manually free the heap storage claimed by 'structure'. I don't think my assumption about garbage is correct. However, I just can't think of how the C-compiler actually handles it. Can some one please disclaim/confirm what I have said. Or even better, can some one please enlighten me to show me how this is really done. Any help or suggestion is GREATLY appreciated. __ ___ ___ _/' Conrad Wong (cwong@cory.berkeley.edu) / \ __/ \----' \-' c`-o | | / > __/_ / __/_`, _| Imitation is the sincerest form of \__/ \_____\`--\____\ ;/' lack of imagination -- Ghondahrl
dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) (05/29/90)
In article <1990May28.215331.29333@agate.berkeley.edu> m100-2ai@WEB.berkeley.edu () writes: > >STRUCT function(void) >{ > STRUCT structure; > > structure.num = 0; > /* Set other fields as well */ > return structure; >} > >Now, it seems that the storage space for 'structure' has to be allocated >on the heap (not on stack). Why? C implementations usually allocate automatic variables on the stack, the fact that it is a structure has nothing to do with this. C is not known for playing with the heap without the user telling it to. The only problem lies in returning a struct value. In an implementation that returns function values in a register, something special must be done to handle return values larger than will fit in that register. One way to do this is to return the address of a block of static memory where the struct can be found and have the calling function copy the value found there into the struct the return value of the function is supposed to be assigned to. Of course, this can lead to a great deal of copying so most of the time you're better off arranging things for the function to have type STRUCT * instead. -- Dave Eisen Home: (415) 323-9757 dkeisen@Gang-of-Four.Stanford.EDU Office: (415) 967-5644 1447 N. Shoreline Blvd. Mountain View, CA 94043
pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (05/29/90)
In article <1990May28.215331.29333@agate.berkeley.edu> m100-2ai@WEB.berkeley.edu () writes: >in ANSI C, I can define a function returning STRUCT, such as the following: > >STRUCT function(void) >{ > STRUCT structure; > > structure.num = 0; > /* Set other fields as well */ > return structure; >} > >Now, it seems that the storage space for 'structure' has to be allocated >on the heap (not on stack). However, wouldn't this create a lot of No, that's not how it's done. I thought it was handled by having the whole structure pushed on the stack, but it turns out that's not how its done either. I tried this program with Amiga Manx 5.0a: struct foo { int a,b; }; struct foo fooer(void) { struct foo bar = {1,2}; return bar; } main() { struct foo bar; bar = fooer(); } Manx compiled it the same way as the following: struct foo fooer(struct foo *ptr) { struct foo bar = {1,2}; *ptr = bar; return ptr; } main() { struct foo bar; fooer(&bar); } So that's one way to do it. I tried this gcc on a VAX, and it handled it by returning the structure in r0 and r1. I made the structure much bigger (too big to fit in registers), and gcc compiled it pretty much the same way as above. -- Paul Falstad PLINK:Hypnos GEnie:P.FALSTAD net:pfalstad@phoenix.princeton.edu Disclaimer: My opinions, which belong to me and which I own, are mine. -Anne Elk (not AN elk!) The sun never set on the British empire because the British empire was in the East and the sun sets in the West.
henry@utzoo.uucp (Henry Spencer) (05/29/90)
In article <1990May28.215331.29333@agate.berkeley.edu> m100-2ai@WEB.berkeley.edu () writes: >...in ANSI C, I can define a function returning STRUCT... >Now, it seems that the storage space for 'structure' has to be allocated >on the heap (not on stack). However, wouldn't this create a lot of >garbages you won't be able to free? ... It would, but that's not how it's done. Returning a struct value *is* tricky, and compilers use a variety of methods, but allocating heap space is generally not acceptable, and allocating space that doesn't get freed is definitely not acceptable. The best method is for the caller, knowing it's calling a struct-valued function, to allocate some space for the return value, and either do this in a known place or else pass an extra parameter which is a pointer to the space. Then the called function just puts the return value there. This does fall down badly if the user does not bother to declare that he's calling a struct-valued function, but that comes under the heading of "if you lie to the compiler, it will get its revenge". -- As a user I'll take speed over| Henry Spencer at U of Toronto Zoology features any day. -A.Tanenbaum| uunet!attcan!utzoo!henry henry@zoo.toronto.edu
meissner@osf.org (Michael Meissner) (05/30/90)
In article <18222@well.sf.ca.us> rld@well.sf.ca.us (Rick Davis) writes: | In article <1990May28.235336.5338@Neon.Stanford.EDU>, Dave Eisen writes: | > | > Of course, this | > can lead to a great deal of copying so most of the time you're better off | > arranging things for the function to have type STRUCT * instead. | > | | I can't agree with this too strongly. Passing entire structures back | and forth is almost always a serious waste of time and stack space. | Indeed, there are circumstances where it is necessary, (i.e communications) | but most of the time you're much better off with the structure pointer. | Also, some implementations of C won't even let you try. Code portability | alone works for me. But a clever compiler could optimize: struct foo func(), var; var = func(); and pass the address of var (assuming it returns structures by passing a pointer as a hidden argument), so that a temporary and a structure copy are not required. -- Michael Meissner email: meissner@osf.org phone: 617-621-8861 Open Software Foundation, 11 Cambridge Center, Cambridge, MA Catproof is an oxymoron, Childproof is nearly so
karl@haddock.ima.isc.com (Karl Heuer) (05/31/90)
In article <8048@crdgw1.crd.ge.com> larocque@jupiter.crd.ge.com (David M. LaRocque) writes: >I think I must be missing something fundamental in the way >storage allocation works. I see how malloc() can return >"permanant" storage in memory that the caller knows won't >get overwritten until free() is called, at least I think I >understand the K&R II description of their malloc routine (pg 185). >However, in the above approach, how can a caller be sure that >makepoint() returned memory that won't get trounced somehow? The usual implementation is that the caller supplies the storage space. >In addition if a point is no longer needed is there a method >analagous to free() that can be used to return the point's >memory to the operating system? No need. The caller knows when it's done with it (usually by the end of the next operator). Note that in struct point p; p = make_point(x, y); the contents are being copied, not the address, so the temporary storage may be reclaimed immediately afterwards (regardless of the lifetime of `p'). Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint
steve@taumet.COM (Stephen Clamage) (05/31/90)
In article <8048@crdgw1.crd.ge.com> larocque@jupiter.crd.ge.com (David M. LaRocque) writes: >One instance I thought of that one may want to use a function that >returns a structure is as an alternative to malloc. > >struct point { int x; int y; }; >struct point makepoint(int x, int y); >struct rect { struct point pt1; struct point pt2; }; >struct rect screen; >screen.pt1 = makepoint(0, 0); In this example, the return from makepoint() is copied to a static (in this case global) variable. Following the call to makepoint, what it actually returned is irrelevant, since it can no longer be referenced. The copy stays where it is (in this case, globally available until the end of the program). If you had a local struct assigned the return from makepoint(), that local struct would contain the value until it's containing function returned, at which time it would disappear. Think about a function returning an int. Where is the int located? Can it be clobbered later? Any function return value must be used (copied) immediately as part of the expression calling the function. This is as true for structs as for ints. -- Steve Clamage, TauMetric Corp, steve@taumet.com
siegel@stsci.EDU (Howard Siegel) (06/01/90)
Conrad Wong (cwong@cory.berkeley.edu) writes: >The following seems to be an "easy" question. However, after thinking >about it, I find that I don't really understand how it really works... > > [simple stuct declaration and function returing struct...] > >Now, it seems that the storage space for 'structure' has to be allocated >on the heap (not on stack). However, wouldn't this create a lot of >garbages you won't be able to free? For example: > > [other stuff...] > >I don't think my assumption about garbage is correct. However, I >just can't think of how the C-compiler actually handles it. Can >some one please disclaim/confirm what I have said. Or even better, >can some one please enlighten me to show me how this is really done. I can not say that all C compilers work this way, but on VMS (any version) this is the story. (Note that this is (should) be the same for all languages that adhere to DEC's Common Calling Convention which is documented someplace in the umpteen feet of manuals). At least for the example in question, I have tried it out and looked at the machine code created by the VAX C compiler. For functions that return a simple (atomic?) data type, the returned value is put into register 0 if it is 4 bytes or smaller or into the register 0/1 pair if it is 5-8 bytes big. If the value to be returned is bigger than 8 bytes then the compiler shifts the argument list over and creates a new first argument which is a pointer to an object of the proper data type. Thus, if the function in question is defined in the code as: STRUCT function(int number) the compiler will create code as if the function were defined as: void function(STRUCT *structure, int number) In the calling routine, the compiler creates a temporary variable for the return value on the stack (not the heap) and uses that variable in the actual function call argument list. Again, this is just how it happens on VMS and with the VAX C (not quite ANSI) compiler. Your mileage with other OS's will vary, but I would imagine they'll act similarly. (Sorry I could not provide compiler listings with the machine code in them, but the link to the VMS machine is flaky at the moment). -- Howard Siegel (301) 338-4418 TRW c/o Space Telescope Science Institute Baltimore, MD 21218 ARPA: siegel@stsci.edu SPAN: STOSC::SIEGEL uucp: {arizona,decvax,hao}!noao!stsci!siegel
scott@bbxsda.UUCP (Scott Amspoker) (06/06/90)
In article <18222@well.sf.ca.us> rld@well.sf.ca.us (Rick Davis) writes: >> Of course, this >> can lead to a great deal of copying so most of the time you're better off >> arranging things for the function to have type STRUCT * instead. > >I can't agree with this too strongly. Passing entire structures back >and forth is almost always a serious waste of time and stack space. ...unless the structure can fit in a single word. I've seen compilers which handle that rather nicely. >Also, some implementations of C won't even let you try. Code portability >alone works for me. We been porting our C code to dozens of different platforms and C compilers for the *past 5 years* and have never encountered a C compiler that did not allow structure assignment. Much older compilers, however, might complain. Such compilers typically conform to old K&R and also don't maintain separate name spaces for structure field names. That's asking too much for portability IMHO. -- Scott Amspoker Basis International, Albuquerque, NM (505) 345-5232 unmvax.cs.unm.edu!bbx!bbxsda!scott