Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!usc!wuarchive!zaphod.mps.ohio-state.edu!pacific.mps.ohio-state.edu!linac!att!ucbvax!microsoft.UUCP!davewh From: davewh@microsoft.UUCP Newsgroups: comp.sys.apple2 Subject: Re: HLLs vs Assembly Message-ID: <9104191553.AA06862@beaver.cs.washington.edu> Date: 18 Apr 91 12:15:57 GMT Sender: daemon@ucbvax.BERKELEY.EDU Organization: The Internet Lines: 128 Raymond Lang asks me (and I answer): : >struct foo * NewFoo(void) : >{ : > struct foo TheNewFoo; : : > TheNewFoo.member1 = value1; : > TheNewFoo.member2 = value2; : : > return &TheNewFoo; : >} : : >Do you know why this will FAIL? Do you know the RIGHT way to do it? : : I'm new at this. What's the problem? OK, C compilers are pretty simple and predicatable. In fact, Pascal compilers are very similar. At any rate, they all "create" local variables on the stack. When a procedure call is made, the calling function pushes its parameters on the stack and then calls the function. The function then pushes dummy stuff onto the stack to allocate enough space for its local variables. So, upon entry to NewFoo, the top of stack contains the return address for the function call (no parameters). NewFoo then pushes enough space onto the stack to hold one foo struct. Members are now set. Look what's returned: the address of TheNewFoo, a pointer to some location on the stack (more accurately, a pointer to some memory currently being used by the stack - memory that will be used again by the stack). The calling function gets this pointer back and does what it pleases. What happens when another function is called? Well, the stack is overwritten (more accurately, the memory where the stack is is changed). But that pointer I have is supposed to point to some valid data! The pointer is still OK, but the data has been corrupted because the next function call has changed the contents of the memory where the stack is (and where my struct is)! OK, you say. Don't pass back a pointer. C can pass whole structs around. So, I change my function to pass back a struct instead of a pointer to a struct. Well, that'll work. No problem there. The only reason I wouldn't do it that way is because what if the struct is HUGE? Passing structs around is terribly inefficient. Lots and lots of bytes have to copied. You also get into very hairy stuff if the struct contains pointers. How do you "copy" the struct? Do you copy the pointers only or do you allocate new memory and copy what the pointers point to? It depends. My solution is this: struct foo * NewFoo(void) { struct foo *TheNewFoo = malloc(sizeof(struct foo)); TheNewFoo->member1 = value1; TheNewFoo->member2 = value2; return TheNewFoo; } Subtle difference here. In this case, I've called the memory manager and asked it for some memory. Assuming the memory manager works correctly (which, by the way, on Sun OS 4.1, it does not - it allocates n-1 bytes for you; the last byte of the memory you ask for isn't there!), this is a safe thing to do. No other function in the computer will deliberately interfere with this chunk of memory. It's *not* on the stack, it's in the heap - a seperate section of memory that the runtime system manages. Should the stack grow so large that it runs into the heap, the program will crash - the runtime system will cause it to crash with a stack overflow error. (This assumes that you're running on a system that can handle an "infinite" stack. Mac's and IIgs's have a much smaller limit and you may overflow that stack long before it runs into the heap.) Since I've manually allocated new memory, I can pass that pointer around with confidence. All I need to do is remember to ask the memory manager to free up that memory when I'm done with it. On unix systems (and other multitasking environments), you can get away with not freeing the memory because usually, when a program exits, all of the space it asked for is freed automatically. This may or may not be the case with the Mac or IIgs (I don't know). Not freeing your memory could cause a memory leak and eventually your machine would fill up with garbage and you'd run out of memory. LESSON: don't return local struct variables. Manually allocate new memory and return a pointer to it. : > Then they learn the language of choice for CS : >majors. The one where the compiler is much more friendly than a C : >compiler but the students still know the pitfalls (why the thing has : >to freeze up every now and then and garbage collect, etc). : : What language is that? Most (not all) would agree, LISP. LISP handles a lot of this memory management crap for you. Allocations in the heap are done behind your back. On the downside, freeing is not automatic and there's no way to do it manually. Therefore, the machine runs out of memory. BUT, because the system knows that it's very likely that you haven't REALLY run out of memory, it does what's called a garbage collect. It examines its list of pointers to objects and the allocated memory. It does some shuffling around and pushing back and forth and discovers allocated memory that has absolutely no pointer pointing to it. OOPS. Free it. After scanning like this, memory is compacted so new allocations can be made easily. Symbolics LISP machines may be set up to do quick and dirty garbage collection while your program is running. This gives you a slight reduction in performance while giving you more time before a heavy-duty garbage collect needs to be done. The heavy duty garbage collect stops the system completely while it shuffles. This can take a couple of hours (I've seen a machine tied up for 4 hours just garbage collecting). You can make the machine NOT EVER do garbage collection, but that isn't wise. The machine just goes right down the toilet. You get panic messages saying "There's only 180K left!" "There's only 100k left!" "There's only 60k left!" "There's only 10k left!" GRONK! Machine crashes. LESSON: no lanuage is perfect for everything. It depends on what you want to do and how much operating responsibility you want to take on for yourself. Dave Whitney Microsoft Corp, Work Group Apps dcw@goldilocks.lcs.mit.edu or I wrote Z-Link and BinSCII - send me bug reports. {...}!uunet!microsoft!davewh I only work here. All opinions herein aren't Bill's, they're mine. "We're samplin' - Yeah we're doin' it. We take good music an' we ruin it." -- "Rap Isn't Music"