karl@haddock.ima.isc.com (Karl Heuer) (03/15/90)
In article <1990Mar14.164539.23685@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >There is absolutely nothing wrong with having a pointer representation in >which the bit pattern for a null pointer is not all zeros... except that >there are a lot of old, badly-written programs which will break. Thus my >earlier comment that it is valid but unwise. Note that "p = 0", "p == 0", "!p", "char *f() { return 0; }" are *not* examples of such badly-written code; they may be bad style, but the compiler is required to generate correct code involving a true null pointer. The only "dangerous" context (other than hacking with unions and such) is when a null pointer constant is being passed as an argument to a function. (In C++ and ANSI C, any argument not covered by a prototype. In old C, any function argument at all.) In particular, neither of the two calls execl("/bin/sh", "sh", "-i", 0); execl("/bin/sh", "sh", "-i", NULL); is correct; it should be written as either of execl("/bin/sh", "sh", "-i", (char *)0); execl("/bin/sh", "sh", "-i", (char *)NULL); But this problem can occur even without strange null pointers: such sloppy code will already break on certain implementations where pointers and ints have different lengths. Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint Followups to comp.lang.c.
williams@umaxc.weeg.uiowa.edu (Kent Williams) (03/15/90)
In article <16179@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: >In article <1990Mar14.164539.23685@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >>There is absolutely nothing wrong with having a pointer representation in >>which the bit pattern for a null pointer is not all zeros... except that >>there are a lot of old, badly-written programs which will break. Thus my >>earlier comment that it is valid but unwise. > >Note that "p = 0", "p == 0", "!p", "char *f() { return 0; }" are *not* >examples of such badly-written code; they may be bad style, but the compiler >is required to generate correct code involving a true null pointer. The bottom line in actual practice is that if NULL isn't a binary object of all zero bits, you can get into trouble porting programs. Using 0 and NULL interchangebly is an unfortunate but common practice -- see code examples in Stroustroup's C++ book -- many assignments of 0 to pointers. In order to port a program to a not-all-zero-bits-NULL architecture would be aided by a compiler that would flag ALL assignments of non-pointer constants to pointer variables. This wouldn't solve all problems, since you can have a function like: void assign_int_to_pointer(void **x, int y) { *x = (void *)y; } Then your compiler would have to generate RUN-TIME checks of values passed in. To muddy the waters further, It isn't uncommon (and not terribly unportable) to use a set of small integral constants, say 0 .. 10 as sentinel values assigned to pointers, e.g. switch((int)ptr) { case 0: do0(); break; case 1: do1(); break; . . . default: it_really_is_a_pointer(ptr); } When discussing these issues, you do have to take into account actual practice, whether actual practice is a good idea in the final analysis or not. -- Kent Williams "We're One! All One! Exceptions Eternally? williams@umaxc.weeg.uiowa.edu None! Absolutely None!" - Dr. Bronner's Soap
john@hcr.uucp (John R. MacMillan) (03/16/90)
Karl Heuer <karl@haddock.ima.isc.com> writes: |>There is absolutely nothing wrong with having a pointer representation in |>which the bit pattern for a null pointer is not all zeros... except that |>there are a lot of old, badly-written programs which will break. Thus my |>earlier comment that it is valid but unwise. | |Note that "p = 0", "p == 0", "!p", "char *f() { return 0; }" are *not* |examples of such badly-written code; they may be bad style, but the compiler |is required to generate correct code involving a true null pointer. The only |"dangerous" context (other than hacking with unions and such) is when a null |pointer constant is being passed as an argument to a function. ``Zeroing out'' pointers with memset, bzero, or calloc is another all-too-common problem. -- John R. MacMillan | "All the best freaks are here; please stop staring HCR Corporation | at me." {utzoo,utcsri}!hcr!john | -- Marillion
jenkins@jpl-devvax.JPL.NASA.GOV (Steve Jenkins) (03/16/90)
Instructions for posting comments on the relationships among 0, NULL, and nil pointers: 1. Read K&R2. Carefully. 2. Read Chris Torek's postings on the subject. You won't have to go back very far -- this comes up about every two months. 3. Read Doug Gwyn's postings on the subject. 4. Still want to post? Go to step 1. 5. Resume normal net reading. -- Steve Jenkins N6UNI jenkins@jpl-devvax.jpl.nasa.gov Caltech/Jet Propulsion Laboratory (818) 354-0162
karl@haddock.ima.isc.com (Karl Heuer) (03/16/90)
In article <945@ns-mx.uiowa.edu> williams@umaxc.weeg.uiowa.edu.UUCP (Kent Williams) writes: >The bottom line in actual practice is that if NULL isn't a binary object >of all zero bits, you can get into trouble porting programs. Using 0 and >NULL interchangebly is an unfortunate but common practice -- see code >examples in Stroustroup's C++ book -- many assignments of 0 to pointers. As I just finished saying, those are quite legal and do not cause a problem on "strange-NULL" implementations. (I presume we're talking about *constant* 0.) >would be aided by a compiler that would flag ALL assignments of >non-pointer constants to pointer variables. I would hope that *any* modern compiler would flag a pointer-vs-int collision! >[An explicit pointer-to-integer cast can still cause problems] >[Also, some programs use small integer constants as sentinels] I'll admit that these two are problem situtations, but I doubt they're all that common. And you don't have to have a "strange-NULL" architecture for them to break. Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint
goudreau@larrybud.rtp.dg.com (Bob Goudreau) (03/16/90)
In article <945@ns-mx.uiowa.edu>, williams@umaxc.weeg.uiowa.edu (Kent Williams) writes: > In article <16179@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: > >In article <1990Mar14.164539.23685@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: > >>There is absolutely nothing wrong with having a pointer representation in > >>which the bit pattern for a null pointer is not all zeros... except that > >>there are a lot of old, badly-written programs which will break. Thus my > >>earlier comment that it is valid but unwise. > > > >Note that "p = 0", "p == 0", "!p", "char *f() { return 0; }" are *not* > >examples of such badly-written code; they may be bad style, but the compiler > >is required to generate correct code involving a true null pointer. > > The bottom line in actual practice is that if NULL isn't a binary object > of all zero bits, you can get into trouble porting programs. Using 0 and > NULL interchangebly is an unfortunate but common practice -- see code > examples in Stroustroup's C++ book -- many assignments of 0 to > pointers. Sigh... Looks like it's time for Chris Torek to repost his explanation of NULL and 0.... ------------------------------------------------------------------------ Bob Goudreau +1 919 248 6231 Data General Corporation 62 Alexander Drive goudreau@dg-rtp.dg.com Research Triangle Park, NC 27709 ...!mcnc!rti!xyzzy!goudreau USA
das@lanai.cs.ucla.edu (David Smallberg) (03/17/90)
In article <1990Mar14.164539.23685@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >There is absolutely nothing wrong with having a pointer representation in >which the bit pattern for a null pointer is not all zeros... except that >there are a lot of old, badly-written programs which will break. Thus my >earlier comment that it is valid but unwise. I've seen "the constant 0" misinterpreted in this way: thing *array[100]; /* clear array to NULLs */ <-- WRONG (void) memset(array,0,sizeof(array)); or (void) memset(array,NULL,sizeof(array)); The offender believes that since he's using the constant 0, the compiler will use the appropriate bit pattern for a NULL pointer, even if that's not all-zero-bits. -- David Smallberg, das@cs.ucla.edu, ...!{uunet,ucbvax,rutgers}!cs.ucla.edu!das
throopw@sheol.UUCP (Wayne Throop) (03/18/90)
> From: guy@auspex.auspex.com (Guy Harris) >> I'm confused, is a non zero NULL pointer valid or not? > The confusion stems from confusion over the meaning of "non-zero". While what Guy says in explanation is certainly correct, I think that the confusion is over the meaning of "NULL pointer", not non-zero. That is, Guy explained things thoroughly, but the basis of the problem is the distinction between properties of a name of a thing and properties of the thing itself. In the phrase "NULL pointer" in C, there are TWO levels of naming going on, either one of which could have the property "zeroness". Or let me put it this way. In C, the name of the nil pointer is called "NULL". But that's only what the name is CALLED, you see. The NAME of the nil pointer is "0". The nil pointer itself can have any bit pattern it pleases. The above sequence of statements explains 1) why NULL should only be used as a pointer (this is a convention). It shouldn't be used to mean ascii NUL 2) why the only proper definition of the macro NULL is the string "0". (or, actually, any way to spell the constant zero in C) (though, granted, the advent of ANSI C means that the best definition of NULL is arguably the string "((void*)0)" and variants on this theme. Nevertheless "0" remains proper.) 3) in just what way C's nil pointer may have a non-zero bit pattern. It omits explanations of why one should never (in K&R1 C) pass NULL as an argument without a cast to a specific pointer type. It also omits explanation of the fact that there isn't really one nil pointer, or (necessarily) one nil pointer bit pattern. (This is due to the fact that all pointer values in C have specific types.) So, to conclude, "NULL", in C should never have a "non-zero" definition. Any particular nil pointer value (eg, one named ((void*)0)) can have any bit pattern the implementor of a C language system chooses. -- Wayne Throop <backbone>!mcnc!rti!sheol!throopw or sheol!throopw@rti.rti.org
karl@haddock.ima.isc.com (Karl Heuer) (03/19/90)
In article <1990Mar15.184903.3397@hcr.uucp> john@troch.UUCP (John R. MacMillan) writes: >Karl Heuer <karl@haddock.ima.isc.com> writes: >|The only "dangerous" context (other than hacking with unions and such) is >|when a null pointer constant is being passed as an argument to a function. > >``Zeroing out'' pointers with memset, bzero, or calloc is another Right. I had a hunch I was overlooking something! Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint
boyd@necisa.ho.necisa.oz (Boyd Roberts) (03/20/90)
In article <945@ns-mx.uiowa.edu> williams@umaxc.weeg.uiowa.edu.UUCP (Kent Williams) writes: > >To muddy the waters further, It isn't uncommon (and not terribly >unportable) to use a set of small integral constants, say 0 .. 10 as >sentinel values assigned to pointers, e.g. > > switch((int)ptr) { > case 0: do0(); break; > case 1: do1(); break; > . > . > . > default: > it_really_is_a_pointer(ptr); > } > Have you _completely_ lost your marbles? The above is one of the most disgusting and unportable constructs I've ever seen. How do you know what integer representations a pointer may have, unless you know the target machine's architecture? This sort of language abuse is sure to lay traps that will be sprung when least expected. Such code would probably pass most acceptance tests, but would fail catastrophically at some later time. Do you really find it acceptable to write code that has such potential for failure? Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...''