Path: utzoo!mnetor!uunet!husc6!cmcl2!brl-adm!umd5!ames!amdahl!dlb!megatest!djones From: djones@megatest.UUCP (Dave Jones) Newsgroups: comp.lang.c Subject: Re: exit(main(argc,argv,env)); Message-ID: <171@goofy.megatest.UUCP> Date: 22 Dec 87 23:41:26 GMT References: <1451@houdi.UUCP> Organization: Megatest Corporation, San Jose, Ca Lines: 97 in article <1451@houdi.UUCP>, marty1@houdi.UUCP (M.BRILLIANT) says: > >> >> I was looking through the file crt0.c in the GNU emacs source code and >> found the command >> >> exit(main(argc,argv,env)); >> >> which I find puzzling. I thought that one was supposed to give exit a >> number for an argument. What does the above command do and why would >> anyone want to do it that way ? >> >> ADLER1@BRANDEIS.BITNET > > Yeah, I second the question. What this does is execute main(...) and > then give exit() the number that main returns. So main(...) must have > in it some statements of the form return(3); or return(status); so that > exit() will get a useful number. But the same effect would be achieved > if main() had statements of the form exit(3); or exit(status);. > > The key question is where the exit(main(..)) was found. Since main() > is the first function called, no statement is needed to invoke main(). > Put it another way, since main() is invoked anyway, any statement that > calls main() must call it recursively. Why would anybody do that? > > M. B. Brilliant Marty > AT&T-BL HO 3D-520 (201)-949-1858 > Holmdel, NJ 07733 ihnp4!houdi!marty1 Don't count on anything in GNU emacs being what it appears to be. Our GNU emacs guru ("gnuru?") was gone for a couple of weeks, and I found myself with the job of fixing a bug. I chased it down, and it seemed to indicate a new static variable. So I added one. When the new version of emacs came up, it crashed, on entry... long before it could have gotten to any reference to the new variable. I tried running it under dbx. dbx crashed. Much head-scratching later, I discovered that when you add a new static variable, you have to do some extra magic... I forget just what. Seems there is a step in the making of a new emacs that edits the a.out file. Probably for purposes of runtime garbage collection. So it is quite possible that some step in the "make" is changing the name of "main" to "foo", or "bar" to "main" or something. There is also a concept of a "recursive edit" in emacs. Maybe that's it. The bad news is that our gnuru has now gone on to different pastures of an indeterminate shade of green. I hope that was the last bug in gnuemacs. New subject: As to why main() should return something rather than just call exit(). I suspect that before stdio, there was no "exit()". Old-timers, is that true? Anyway, all that the Berkeley 4.2 exit() does is to flush all the stdio buffers, then call _exit(). Problem is, stdio is not unique in requiring some clean-up upon any exit from the program. I confess that I have on occasion used my own a.out editor to change the name of the C-library's exit() "Cexit" or whatever, then written my own exit() which does some cleanup then calls the (now) Cexit routine. Simpler than trying to police the use of exit() by a dozen or so fellow programmers. Moral: Start a company policy of not using exit(). Call Lexit() instead. Have a way of registering cleanup routines with Lexit. A possible solution: /* No, I have not tested this, so if it's buggy, it's buggy. */ static int (*cleanup)(); int (*)(); set_Lexit(new_cleanup) int (*new_cleanup)(); { int (*old_cleanup)() = cleanup; cleanup = new_cleanup; return old_cleanup; } Lexit(code) { if(cleanup) (*cleanup)(code); exit(code); } /* use.... */ static int (*next_cleanup)(); foo_cleanup(code) { /* do my cleanup then... */ (*next_cleanup)(); } bar() { next_cleanup = set_Lexit(foo_cleanup); /* do stuff ... */ }