ericb@libdev (Eric Bivona) (11/23/88)
I have a question about tests on pointers, w.r.t. the ANSI standard
for C.
I know about casting NULL or 0 to get an appropriate nil pointer to
test against:
char *ptr;
void *malloc();
ptr = (char *)malloc(256); /* or (size_t)256? ;-) */
if (ptr == (char *)0) { /* or (char *)NULL */
perror("malloc");
exit(1);
}
In assignments, a 0 or NULL is cast implicitly to the correct pointer
type (I think, please correct me if I'm wrong). What about the '=='
comparison above? Would "(ptr == 0)" get evaluated correctly? Or to
push it a bit further, what about the VAX-ish standard (like
*(char *)0 = 0 ;-) "(!ptr)"? I realize that it is probably better to
explicitly cast & compare, but it did kind of make sense to say "if
(!ptr)..."
Thanks in advance,
-Eric Bivona
DCIS Project, Dartmouth College
chris@mimsy.UUCP (Chris Torek) (11/23/88)
In article <11130@dartvax.Dartmouth.EDU> ericb@libdev (Eric Bivona) writes: >I know about casting NULL or 0 to get an appropriate nil pointer ... Note that a cast is always sufficient, if not always necessary. (I find that much `extra' casting hampers readability, though.) [edited] > if (ptr == (char *)0) { /* or (char *)NULL */ >In assignments, a 0 or NULL is cast implicitly to the correct pointer >type .... Right. >What about the '==' comparison above? Would "(ptr == 0)" get evaluated >correctly? It would; the implicit cast occurs here, too. >... what about ... "(!ptr)"? That too is correct, by the rule that `!x' means `x == 0'. Stylistically, though, I prefer `if (ptr == NULL)'. In fact, the only place that `0' does not implicitly turn into the right kind of `nil' is in function calls (and, under dpANS rules, only those where prototypes are not present or insufficient to convey the necessary type information). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/23/88)
In article <11130@dartvax.Dartmouth.EDU> Eric.J.Bivona@Dartmouth.EDU writes: >I have a question about tests on pointers, ... if ( !ptr ) and if ( ptr == 0 ) are both perfectly valid ways to test for a null pointer. You can explicitly cast the 0 to the proper type, but it's not necessary. Explicit casting of 0 (or NULL, defined in several headers) is required only when the compiler could mistake the 0 for an int constant rather than the intended null pointer constant. The main place this can occur is in the arguments to a function when no prototype is in scope, e.g. execl( "/bin/sh", "-sh", "-i", 0 ); (This one is even worse since it's a variable-argument function, so not even a prototype would help.) The bug typified by this is seen in a LOT of code ("well it worked on MY machine!").
guy@auspex.UUCP (Guy Harris) (11/24/88)
>In assignments, a 0 or NULL is cast implicitly to the correct pointer >type (I think, please correct me if I'm wrong). This is correct. >What about the '==' comparison above? Would "(ptr == 0)" get evaluated >correctly? In any valid C implementation, it will be. The compiler certainly knows enough to do the implicit conversion, just as it does in the case of an assignment. >Or to push it a bit further, what about the VAX-ish standard (like >*(char *)0 = 0 ;-) "(!ptr)"? I realize that it is probably better to >explicitly cast & compare, but it did kind of make sense to say "if >(!ptr)..." This will also work in any valid C implementation.
dhesi@bsu-cs.UUCP (Rahul Dhesi) (11/25/88)
In article <8961@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: > execl( "/bin/sh", "-sh", "-i", 0 ); >...The bug typified by this is seen in a >LOT of code ("well it worked on MY machine!"). Sadly, the only UNIX programming textbook I've seen on the market, by Rochkind, consistently uses 0 and NULL as actual parameters without any cast. This may be because Rochkind did all his programming using Venix on an IBM XT, and the Venix compiler does not support any memory model in which ints and char pointers are of different sizes. There is probably an entire generation of future programmers ready to graduate and begin planting execl(...., 0) timebombs in production code. -- Rahul Dhesi UUCP: <backbones>!{iuvax,pur-ee}!bsu-cs!dhesi
davidsen@steinmetz.ge.com (William E. Davidsen Jr) (11/29/88)
In article <8961@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: | In article <11130@dartvax.Dartmouth.EDU> Eric.J.Bivona@Dartmouth.EDU writes: | >I have a question about tests on pointers, ... | | if ( !ptr ) | and | if ( ptr == 0 ) | are both perfectly valid ways to test for a null pointer. You can | explicitly cast the 0 to the proper type, but it's not necessary. Doug, as usual you are correct, but I have to point out that if (ptr == NULL) also works, usually generates the same code, and gives a much better idea of what the code is doing. I'm sure that some of the new readers of this group would not quickly grasp the meaning of your first example, and I'm not sure about the second. I just covered this topic in a C course I'm teaching, and I am always amazed at how easily new C programmers are confused by shorthand form which "mean the same thing." -- bill davidsen (wedu@ge-crd.arpa) {uunet | philabs}!steinmetz!crdos1!davidsen "Stupidity, like virtue, is its own reward" -me
bjm@sabin.UUCP (Brendan J. McMahon) (11/30/88)
In article <4860@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: >Sadly, the only UNIX programming textbook I've seen on the market, by >Rochkind, consistently uses 0 and NULL as actual parameters without any >cast. This may be because Rochkind did all his programming using Venix Well, I have learned a great deal from that book. But when verifying your claim, I noticed the use of gets() in his getargs function for his shell! Thank God for USENET gurus to set me straight (or at least getting me so confused that I am forced to verify everything that I read anywhere.) -- Brendan J. McMahon Sabin Metal Corp. | Refiners of Precious Metals | Hardware Trouble? Scottsville, NY | ****** Au Ag Pt Pd Rh ****** | Give us a call, we'll 716-538-2194 |lazlo!sabin!bjm || ritcsh!sabin!bjm| melt your trouble away
gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/01/88)
In article <12690@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes: -In article <8961@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: -| In article <11130@dartvax.Dartmouth.EDU> Eric.J.Bivona@Dartmouth.EDU writes: -| >I have a question about tests on pointers, ... -| if ( !ptr ) -| and -| if ( ptr == 0 ) -| are both perfectly valid ways to test for a null pointer. You can -| explicitly cast the 0 to the proper type, but it's not necessary. -Doug, as usual you are correct, but I have to point out that - if (ptr == NULL) -also works, usually generates the same code, and gives a much better -idea of what the code is doing. I'm sure that some of the new readers of -this group would not quickly grasp the meaning of your first example, -and I'm not sure about the second. I just covered this topic in a C -course I'm teaching, and I am always amazed at how easily new C -programmers are confused by shorthand form which "mean the same thing." I wasn't recommending anything other than if(ptr==NULL) (which requires that the programmer arrange for NULL to be properly defined first, but I always do arrange that for my code). In fact I wasn't making any stylistic suggestion at all, just answering a specific question.
danw@tekchips.CRL.TEK.COM (Daniel E. Wilson) (12/01/88)
In article <494@auspex.UUCP>, guy@auspex.UUCP (Guy Harris) writes: > >In assignments, a 0 or NULL is cast implicitly to the correct pointer > >type (I think, please correct me if I'm wrong). > > This is correct. > > >What about the '==' comparison above? Would "(ptr == 0)" get evaluated > >correctly? I tend to avoid the whole problem by defining a simple macro. Simply by using this macro always I get a NULL pointer of the needed type. This does avoid bugs. #define NIL(type) ((type *) NULL) Unless someone would like to give me warnings about the abuses of macros. 8-)
bill@twwells.uucp (T. William Wells) (12/01/88)
In article <12690@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes: : In article <8961@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: : | In article <11130@dartvax.Dartmouth.EDU> Eric.J.Bivona@Dartmouth.EDU writes: : | >I have a question about tests on pointers, ... : | : | if ( !ptr ) : | and : | if ( ptr == 0 ) : | are both perfectly valid ways to test for a null pointer. You can : | explicitly cast the 0 to the proper type, but it's not necessary. : : Doug, as usual you are correct, but I have to point out that : if (ptr == NULL) : also works, usually generates the same code, and gives a much better : idea of what the code is doing. I'm sure that some of the new readers of : this group would not quickly grasp the meaning of your first example, : and I'm not sure about the second. I just covered this topic in a C : course I'm teaching, and I am always amazed at how easily new C : programmers are confused by shorthand form which "mean the same thing." I'm afraid that you've just contributed to the confusion. In the material you quoted, the type of `ptr' is not specified. That being the case, if (ptr == 0) is not equivalent to if (ptr == NULL) They are only equivalent if the type of ptr is `void *' or `char *'. Otherwise, there are are implementations, those defining NULL as (char *)0, which will give an error on the latter statement. To set the record straight, these are all equivalent: if (!ptr) if (ptr == 0) if (ptr == (the_type_of_ptr)0) if (ptr == (the_type_of_ptr)NULL) If ptr is of type `void *' or `char *' then the following is also equivalent: if (ptr == NULL) --- Bill {uunet|novavax}!proxftl!twwells!bill
shirono@hcx3.SSD.HARRIS.COM (12/01/88)
In comp.lang.c, bill@twwells.uucp writes: > In article <12690@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes: > : In article <8961@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: > : | In article <11130@dartvax.Dartmouth.EDU> Eric.J.Bivona@Dartmouth.EDU writes: > : | >I have a question about tests on pointers, ... > : | > : | if ( !ptr ) > : | and > : | if ( ptr == 0 ) > : | are both perfectly valid ways to test for a null pointer. You can > : | explicitly cast the 0 to the proper type, but it's not necessary. > : > : Doug, as usual you are correct, but I have to point out that > : if (ptr == NULL) > : also works, usually generates the same code, and gives a much better > : idea of what the code is doing. > > I'm afraid that you've just contributed to the confusion. In the > material you quoted, the type of `ptr' is not specified. That being > the case, > > if (ptr == 0) > > is not equivalent to > > if (ptr == NULL) > > They are only equivalent if the type of ptr is `void *' or `char *'. > Otherwise, there are are implementations, those defining NULL as > (char *)0, which will give an error on the latter statement. WRONG. I'm afraid you may have lost some context, but the original poster (Eric.J.Bivona@Dartmouth.EDU) asked his question in the framework of ANSI C. Doug Gwyn's answer is (of course) correct, and Bill Davidsen's remark, while reflecting an opinion, is correct in implementation (i.e, if (ptr == NULL) is correct). Even in the K&R1 days, the only valid definition of NULL has been #define NULL 0 Any other implies a broken compiler/compilation-environment, and should be discarded. --Roberto ______________________________________________________________________________ || Internet: shirono@ssd.harris.com Roberto Shironoshita || Harris Corporation || ...!novavax---\ Computer Systems Division || UUCP: ...!uunet-------!hcx1!shirono || ...!mit-eddie-/ ------------------------------------------------------------------------------ DISCLAIMER: The opinions expressed here are my own; they in no way reflect the opinion or policies of Harris Corporation.
gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/02/88)
In article <226@twwells.uucp> bill@twwells.UUCP (T. William Wells) writes: >Otherwise, there are are implementations, those defining NULL as >(char *)0, which will give an error on the latter statement. The only valid definitions for NULL are 0 and ((void*)0). As you say, implementations exist that do this wrong.
tps@chem.ucsd.edu (Tom Stockfisch) (12/02/88)
In article <3340@tekcrl.CRL.TEK.COM> danw@tekchips.CRL.TEK.COM (Daniel E. Wilson) writes: >In article <494@auspex.UUCP>, guy@auspex.UUCP (Guy Harris) writes: >> >In assignments, a 0 or NULL is cast implicitly to the correct pointer > > I tend to avoid the whole problem by defining a simple macro. Simply >by using this macro always I get a NULL pointer of the needed type. >This does avoid bugs. > > #define NIL(type) ((type *) NULL) It also doesn't always work, e.g. NIL( int (*)[5] ) or NIL( void (*)() ) I use (type *)0 when passing arguments and NULL everywhere else (except, of course, the null character should be written '\0'). Then noone has to look up NIL() in a header file, I don't have to make sure the header file is included in virtually every source file I write, and it always works. -- || Tom Stockfisch, UCSD Chemistry tps@chem.ucsd.edu
guy@auspex.UUCP (Guy Harris) (12/02/88)
>Otherwise, there are are implementations, those defining NULL as >(char *)0, which will give an error on the latter statement. Great! That means that if I get an error, I get to throw rotten eggs at the implementor. It's a good test to see who understood what they were doing when they implemented C.... If NULL is properly defined as specified by the dpANS, namely as 0 or "(void *)0", if (ptr == 0) and if (ptr == NULL) are equivalent.
gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/02/88)
In article <44100016@hcx3> shirono@hcx3.SSD.HARRIS.COM writes: >Even in the K&R1 days, the only valid definition of NULL has been >#define NULL 0 True of pre-ANSI C, but an ANSI C implementation can use either that definition or #define NULL ((void*)0) I recommend the former even for ANSI C implementations. The added complexity buys just one thing, which is possible type mismatch checking, but I don't think that is significant enough to justify the change.
jwr@scotty.UUCP (Jim Reid) (12/03/88)
In article danw@tekchips.CRL.TEK.COM (Daniel E. Wilson) writes: > > I tend to avoid the whole problem by defining a simple macro. Simply >by using this macro always I get a NULL pointer of the needed type. >This does avoid bugs. > > #define NIL(type) ((type *) NULL) If you were the person who originally posted this macro a couple of years ago, I'd personally like to thank you for it. I've been using it in my code ever since. I haven't come across a better all-purpose pointer type. -- Jim Reid {ames,harvard,rutgers}!rochester!kodak!scotty!jwr --
wald-david@CS.YALE.EDU (david wald) (12/05/88)
In article <9038@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >In article <44100016@hcx3> shirono@hcx3.SSD.HARRIS.COM writes: >>Even in the K&R1 days, the only valid definition of NULL has been >>#define NULL 0 > >True of pre-ANSI C, but an ANSI C implementation can use either that >definition or >#define NULL ((void*)0) >I recommend the former even for ANSI C implementations. The added >complexity buys just one thing, which is possible type mismatch >checking, but I don't think that is significant enough to justify >the change. I may be sorry in the morning for asking this, but: Isn't the latter generally preferable, given its possible use as a parameter for a function with no prototype in scope? Further, isn't the former dangerous in this case, given that there is no guarantee for NULL and (int)0 to have the same representation? ============================================================================ David Wald wald-david@yale.UUCP waldave@yalevm.bitnet ============================================================================
chris@mimsy.UUCP (Chris Torek) (12/05/88)
>In article <9038@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) >writes: >>True of pre-ANSI C, but an ANSI C implementation can use either [#define NULL 0] or >>#define NULL ((void*)0) >>I recommend the former even for ANSI C implementations. ... In article <44803@yale-celray.yale.UUCP> wald-david@CS.YALE.EDU (david wald) writes: >I may be sorry in the morning for asking this, but: Perhaps. >Isn't the latter generally preferable, Not particularly. >given its possible use as a parameter for a function with no >prototype in scope? Unless that function takes a `void *' argument in that position, if the NULL is uncast, the code remains incorrect. The compiler cannot diagnose this since the function might take a `void *' argument in that position. For instance: void ** collect(void *first, ...) { va_list ap; int n; void **p, **q, *t; if (first) { va_start(ap, first); n = 2; while (va_arg(ap, void *) != NULL) n++; va_end(ap); } else n = 1; p = malloc(n * sizeof(void *)); if (p == NULL) return (NULL); q = p; if (first) { *q++ = first; va_start(ap, first); while ((t = va_arg(ap, void *)) != NULL) *q++ = t; } *q = NULL; return (p); } Collect() accepts only `void *'; the end of the list it is to collect into a vector is marked by a nil `void *'. (Incidentally, collect() is another example of why requiring an `anchor' argument for va_start is bad.) >Further, isn't the former dangerous in this case, given that there is >no guarantee for NULL and (int)0 to have the same representation? No more dangerous than the latter, given that there is no guarantee for NULL and NULL (of two different types, e.g., `void *' nil and `struct glorp *' nil) to have the same representation. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/06/88)
In article <44803@yale-celray.yale.UUCP> wald-david@CS.YALE.EDU (david wald) writes: >Isn't the latter generally preferable, given its possible use as a >parameter for a function with no prototype in scope? Further, isn't the >former dangerous in this case, given that there is no guarantee for NULL >and (int)0 to have the same representation? There's also no guarantee that (void *) and other pointer types have the same representation. You MUST cast NULL when using it as a function argument with no prototype in scope. (If it happens to work without a cast, it's an accident. Your program should not rely on accidents to work correctly.)
guy@auspex.UUCP (Guy Harris) (12/06/88)
>Isn't the latter [(void *)0] generally preferable, given its possible >use as a parameter for a function with no prototype in scope? Further, >isn't the former dangerous in this case, given that there is no >guarantee for NULL and (int)0 to have the same representation? There's no guarantee that "(void *)0" and "(type *)0" have the same representation, either, unless "type" is either "char" or "void", as far as I know, so "(void *)0" doesn't guarantee success, either.