Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!lll-lcc!styx!ames!ucbcad!ucbvax!decvax!decwrl!sun!gorodish!guy From: guy%gorodish@Sun.COM (Guy Harris) Newsgroups: comp.lang.c Subject: Re: NULL pointers as arguments Message-ID: <17780@sun.uucp> Date: Fri, 1-May-87 04:29:07 EDT Article-I.D.: sun.17780 Posted: Fri May 1 04:29:07 1987 Date-Received: Sun, 3-May-87 00:40:15 EDT References: <1130@ius2.cs.cmu.edu> <148@nbisos.NBI.COM> <641@gargoyle.UChicago.EDU> Sender: news@sun.uucp Distribution: na Lines: 105 > It is NOT wrong. K & R EXPLICITY state that NULL IS the correct manner in > which to represent this stuff. (K & R p. 97-98): Sorry, that's not in Appendix A; it's exegesis, not prescription. > Point is, we have to live with what C is now and has been in the past. It > doesn't suffice to say "it's wrong." K & R in the famous Appendix A sum it > up (p. 192): > > "...it is guaranteed that assignment of the constant 0 to a pointer will > produce a null pointer distinguishable from a pointer to any object." > > To say code using this fact is "wrong" isn't correct, OR productive. Yes, it *is* correct, and it *is* productive. It's correct because we're not discussing assignments here, we're discussing argument passing. Assignments perform type conversions of various sorts. Argument passing does not perform the same conversions - see p. 186: Any actual arguments of type 'float' are converted to 'double' before the call; any of type 'char' or 'short' are converted to 'int'; and, as usual, array names are converted to pointers. *No other conversions are performed automatically; in particular, the compiler does not compare the types of actual arguments with those of formal arguments. If conversion is needed, sue a cast; see \(sc 7.2, 8.7.* ("italics" mine) Note, BTW, that another conversion not performed is the "int" to "long" conversion; it is no more correct to do setbuf(stdout, NULL); than it is to do lseek(fd, 0, 0); Both are incorrect. It is productive because there *are* implementations of C - legal ones - where you are required to cast your pointers. Throwing in some hack in one implementation to make things "work" without a cast doesn't make incorrect code work on those other implementations. Making the code correct by putting in the cast *does* make the code work on correct implementations. > Useful suggestions (such as common coersion) may be acceptable FOR THE > NULL POINTER case. From K & R, you could assume there was a pointer type > "NULL" which was distinguishable from other pointer types. Thus, a NULL > char * could be the same as a NULL struct x *. You're not using "type" here in the sense of a type in C, which is causing a problem. A NULL "char *" could be the same as a NULL "struct x *", but it *need* not be. If you infer from K&R that there is a pointer type, in the sense of a C language type, NULL, you would be inferring something not implied by K&R. Consider: 7.13 Conditional operator ...otherwise, one must be a pointer and the other the constant 0, and the result has the type of the pointer. This means that if "cp" is of type "char *", then the expression 0 ? cp : 0 has "the type of the pointer", namely "char *", while if "sxp" is of type "struct x *", the expression 0 ? sxp : 0 has the type "struct x *". Both expressions yield null pointers, and both expressions have different types. > Coersion of NULL pointers only may be difficult, but it would conform, > and solve the problem. Coercion of NULL pointers only may or may not be difficult. However, that's irrelevant, because it would break a fair bit of code and would 1) *not* conform to any reasonable specification of C and 2) would cause far more problems than it would solve. How is "f": void f(p) int *p; { ... } supposed to handle calls of the form "f(NULL)" (which would be treated as "f((char *)NULL)" under this proposal) and of the form "f(&x)", unless the "&x" is also coerced to type "char *"? This coercion would be unpleasant on a machine where coercing "int *" to "char *" is not a zero-cost operation, unless (as Tony Hansen pointed out) you were in an ANSI C environment and could use function prototypes to tell the compiler not to perform this coercion in most cases (but you stated that the problem is, in fact, that we don't have an ANSI C standard yet), or (as Chris Torek pointed out) it were a compiler option (which means you'd have to put the casts in anyway unless you wanted to pay the performance penalty of doing the coercion - note also that this would require two versions of your C library, one compiled with this option, and one without).