Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!think!ima!haddock!karl From: karl@haddock Newsgroups: net.lang.c Subject: Re: Orphaned Response Message-ID: <86900019@haddock> Date: Tue, 19-Aug-86 21:26:00 EDT Article-I.D.: haddock.86900019 Posted: Tue Aug 19 21:26:00 1986 Date-Received: Wed, 20-Aug-86 22:46:28 EDT References: <273@watmath.UUCP> Lines: 53 Nf-ID: #R:watmath.UUCP:273:haddock:86900019:000:2814 Nf-From: haddock!karl Aug 19 21:26:00 1986 ccvaxa!aglew (Andy Glew) writes: >[haddock!karl (Karl Heuer) writes:] >>I was trying to declare "typedef void dead;" so that I could distinguish >>between functions that return nothing (void perror(char *), setbuf(FILE *, >>char *), nullf(void)) from those that don't return (dead exit(int), >>abort(void), longjmp(jmp_buf, int)). > >Good point, though - an optimizing compiler could take advantage of >knowledge that a function doesn't return to do better register allocation, >etc. Should this be in the langauge, or is a convention like /*NOTREACHED*/ >enough? (Rhetorical question: obviously, you should specify it at the point >of declaration of such a function, not at the point of use.) I posted this question before, and most of the response was on the order of "this declaration isn't NEEDED". True. But "void" wasn't necessary either; the language lasted quite some time with nonvalued int functions (which are still quite common, especially since "int" is the default datatype). The addition of "void" didn't improve the generated code of any compiler I know (the function and its caller both knew that no value was being used). As far as I can tell, it was added merely to allow clearer code, and to simplify catching certain kinds of errors. The same can be said of boolean expressions and dead functions. The only reasons for not adding them, as far as I can see, are as follows: [0] Inertia, of course. [1] It requires a new keyword (someone suggested that dead functions can be reuse the keyword "goto", but I don't think it's appropriate). [2] It won't be usable much. This is a valid point. There were a *lot* of nonvalued int functions before void was invented; there are only a handful of standard functions that are dead-ends. Booleans are more common, especially in programs like "ls" that have a flag for each option. But I digress. Returning to your comments: as for optimization, the calling function can take advantage of the knowledge by omitting extra branches (e.g. in "if (err) exit(1); else ...") or returns ("exit(0)" at the bottom of main()). This improves the space (but not time) efficiency, but not by much. I presume your comment about register allocation referred to the dead-end itself, in that the caller's registers need not be saved. I don't think you can assume this: the function "dead f() { for (;;) pause(); }" could be interrupted by a signal, whose handler could longjmp() to f's caller, whose registers must be recoverable. For similar reasons, it probably isn't okay to optimize the function call into a jump, unless you're careful with the stack. But I really hate having to write /*NOTREACHED*/ to keep lint happy! Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint (Sorry if I've been rambling; it's late, and I should be in bed.)