Orphaned Response

karl at haddock karl at haddock
Wed Aug 20 11:26:00 AEST 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.)



More information about the Comp.lang.c mailing list