Path: utzoo!utgpu!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!rutgers!mailrus!ncar!tank!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.lang.c Subject: Re: main() and exit() (was: Strange lint mumblings) Message-ID: <15186@mimsy.UUCP> Date: 29 Dec 88 20:53:31 GMT References: <416@marob.MASA.COM> <11467@dartvax.Dartmouth.EDU> <179@amsdsg.UUCP> <7082@batcomputer.tn.cornell.edu> Distribution: na Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 86 In article <7082@batcomputer.tn.cornell.edu> braner@batcomputer.tn.cornell.edu (Moshe Braner) writes: >On systems I have worked on, calling exit() links in most of the >STDIO library modules, resulting in an executable program that is >much bigger than it needs to be (in the case where you don't otherwise >use STDIO). Calling _exit() instead does not link in STDIO. This is the wrong approach (which does not mean that no implementations do it). From a Unix slant, the difference is that exit() flushes buffers iff using stdio, then calls _exit(); _exit() is the process- termination system call. From a dpANS slant, exit() calls the registered atexit() [or is it onexit()?] functions, then causes the program to terminate. >Does YOUR system's startoff code (that calls main()) call exit() or _exit()? Most call exit(). This does not have to suck in all of stdio. Unix systems have used various approaches to accomplish this. With the advent of the dpANS, the simplest approach is to have a single reserved `atexit' slot for stdio, and have exit() provide a way for stdio, if it is ever used, to register its own cleanup routine: /* exit.c */ /* * I have forgotten the details of atexit, so I am assuming * that atexit() registers a (void (*)(void)), and returns * success (0) / failure (nonzero). */ typedef void (*exitfn)(void); static exitfn exit_functions[32]; static int next_exit_fn = 1; /* slot 0 is for stdio */ void __stdio_atexit(exitfn cleanup) { exit_functions[0] = cleanup; } int atexit(exitfn f) { if (next_exit_fn >= sizeof(exit_functions)/sizeof(exitfn)) return (-1); /* no room */ exit_functions[next_exit_fn++] = f; return (0); } void exit(int code) { register int i; /* * Call registered atexit functions, in reverse. * If stdio has registered a cleanup function, it * will be in slot 0 and therefore called last. */ for (i = next_exit_fn; --i >= 0;) if (exit_functions[i] != NULL) (*exit_functions[i])(); /* now really exit */ _exit(code); } Then, in appropriate places within stdio, such as fopen and fdopen: extern void __stdio_cleanup(void); ... __stdio_atexit(__stdio_cleanup); >Do you like the way it is? Yes. >Other related observations/questions: exit() flushes stream I/O buffers. >It also closes the files (releases the descriptors). Who closes non-STDIO >files (the ones you opened with open() rather than fopen())? On my systems >it seems that the OS closes the files . . . . If your system has files, the OS should take care of closing them on program termination. >Finally, what percentage of YOUR programs do NOT use STDIO (buffered >streams, fopen/fread/putc/puts/printf...)? Certainly < 10%. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris