kendall@wjh12.UUCP (Sam Kendall) (10/02/83)
The complaint is that (void) f(); is a kludge, that (*(void (*)()) f)(); /* or something like that */ is the "real" way to do the former. Well, I there is nothing wrong with the former. A void cast means "throw away a value". An interesting point here is that the latter is not even guaranteed to work in the C language. Calling a function with an incorrectly specified type usually works, but on some compilers (National Semiconductor's 16032 C compiler, for instance), if f() returns a structure, then it must be declared to do so for a call to work, since the address of where to put the return value is passed as the first arg of the function. Many programs do not declare the return type of functions correctly; for instance, it is common to leave off a char *strcpy(); definition if the return value is never used. My question is this: What should the language say about calling functions with incorrectly declared return values? We cannot guarantee that it will work with functions returning structures. But should it otherwise? Many programs (unfortunately) depend on it. Sam Kendall {allegra,ihnp4}!wjh12!kendall Delft Consulting Corporation decvax!genrad!wjh12!kendall
guy@rlgvax.UUCP (Guy Harris) (10/03/83)
The language should *not* guarantee that calling a function without having properly declared the type of the function's return value should work, because not all implementations can guarantee this. If pointers and "int"s are different sizes (as they are on several 68000 implementations, on Zilog's segmented Z8000 implementation (I assume), and probably on several other machines with a decently-sized address space but either weak support for 32-bit integers (like the 68K with its lack of 32-bit mul/div) or performance losses for 32-bit integers) if you don't say "char *malloc()" or whatever you are *guaranteed* to lose. Programs which depend on this working should either be changed not to or be hacked on such implementations to use "long"s instead of "int"s. Guy Harris {seismo,mcnc,we13,brl-bmd,allegra}!rlgvax!guy
tim@unc.UUCP (Tim Maroney) (10/05/83)
The cited use of the (void) type cast is indeed incorrect if the operator precedence rules of Kernighan and Ritchie are correct. The example given went like: (void) foo(x); to show that nothing important is returned from foo. In fact, the parentheses of the function call argument list group first, meaning that the value returned by foo is a function of type void. To do it right, you would have to say: ((void) foo)(x); I suppose that the rather sloppy definition of void in the public documentation would allow you to make a weak case for the former being correct, though. Still, special properties of void notwithstanding, only the latter form is correct. Isn't C wonderful? Wait, let me leave the room before you answer... _________________________ Tim Maroney, duke!unc!tim
henry@utzoo.UUCP (Henry Spencer) (10/05/83)
A while ago, I exchanged mail with DMR about the question of whether neglecting to declare the type of an unused return value was a sin. The C book does say that awful things may happen if you get the type wrong (explicitly or implicitly) and use the value, but it is silent on the subject of return values that are merely discarded. Dennis's comments (as nearly as I remember them) were, roughly: "There has been no firm decision on this. It would be a lot cleaner to require proper declaration, but it would break many, many existing programs. There is also an argument which says 'if you don't use it, why should you need to declare it?'." I believe the pragmatic issues involved made him lean toward being permissive about this. It does make life harder for compiler writers, especially with structure returns. About the only thing you can do if your machine is especially recalcitrant is to have the compiler quietly generate an extra little function for each "real" function, with the extra function calling the real one and then properly discarding the returned value. The compiler then calls either the real function or the extra, depending on whether the returned value is used by the particular call or not. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry
kendall@wjh12.UUCP (Sam Kendall) (10/05/83)
The language should *not* guarantee that calling a function
without having properly declared the type of the function's
return value should work, because not all implementations can
guarantee this. If pointers and "int"s are different sizes...
if you don't say "char *malloc()" or whatever you are
*guaranteed* to lose.
Guy Harris
You're absolutely right. In my news item I was referring only to cases
in which the function is defined to return some type, possibly a
structure, but not declared (in another file) to do so, AND the return
value in that file is ignored; and to the language definition issues
raised by such examples. But I didn't make this distinction clear in my
news item.
An example of what I mean:
File "a.c": struct a f()
{
...
}
File "b.c": /* no declaration of f() */
...
f(); /* call to f, return value ignored */
...
This example will fail on those machines which use a hidden first argument
to implement structure returning. But this same lack of declaration is
common for functions which return something other than structures, functions
whose return values are often ignored anyway, such as strcpy(). My question,
then, is what should be guaranteed for such things.
Along these lines, I'd like to see a lint(1) option to warn about default
function and formal parameter declarations, even though they are part of the
language.
Sam Kendall {allegra,ihnp4}!wjh12!kendall
Delft Consulting Corporation decvax!genrad!wjh12!kendall
decot@cwruecmp.UUCP (Dave Decot) (10/07/83)
The form (void) foo(x); as a statement intended to "throw away" the value returned by foo(x) IS correct, because it is a CAST operation on the expression foo(x); which (apparently) has some non-void value. The expression (void) foo(x); still does have a "value" of sorts, but the "value" is of type void, whose "conversion" rules are that any attempt to convert its values to any other type (or to otherwise use void "values") is an error. It is an therefore an ERROR to ask for ((void) foo)(x); because an expression of type void, i.e. ((void) foo) cannot be where a function pointer (like foo) is required. Dave Decot ..!decvax!cwruecmp!decot