Date: Sat, 15 Feb 1997 10:17:23 +1100 From: Giles Lean <giles@nemeton.com.au> To: Eivind Eklund <eivind@dimaga.com> Cc: hackers@freebsd.org Subject: Re: NULL as ((void*)0) (was Re: strlen() question) Message-ID: <199702142317.KAA12738@nemeton.com.au> In-Reply-To: <3.0.32.19970214173652.00c0b290@dimaga.com>
next in thread | previous in thread | raw e-mail | index | archive | help
------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <12731.855962183.1@nemeton.com.au> On Fri, 14 Feb 1997 17:36:53 +0100 Eivind Eklund wrote: > I hereby propose changing the default declaration of NULL under FreeBSD from > #define NULL 0 > to > #define NULL ((void*)0) This is more of a kludge than a good idea, and I offer the following sage advice that I filed away many years ago. Regards, Giles ------- =_aaaaaaaaaa0 MIME-Version: 1.0 Content-Type: message/rfc822 >From rsalz@bbn.com Tue Nov 7 09:35:09 1989 Relay-Version: version Notes 2.8.2 87/11/24; site hpausla.aso.hp.com From: rsalz@bbn.com (Rich Salz) Date: Mon, 6 Nov 1989 22:35:09 GMT Date-Received: Tue, 7 Nov 1989 13:37:34 GMT Subject: Re: NULL Message-ID: <2144@prune.bbn.com> Organization: BBN Systems and Technologies Corporation Path: hpausla!hpcuhc!hpda!hplabs!hp-sdd!ucsdhub!sdcsvax!network.ucsd.edu!ucsd!tut.cis.ohio-state.edu!ukma!mailrus!bbn!bbn.com!rsalz Newsgroups: comp.os.minix References: <4455@ast.cs.vu.nl> Lines: 99 (This is part two of the set-up. Andy and I have exchanged email about this.) I believe that if you have anything other than "#define NULL 0" you are encouraging sloppy non-portable code. Yes, casting 0 all the time is a pain, but c'est la vie. Function prototypes help. When it comes to this topic, Chris Torek is one of the many people who are smarter than I am who are also better writers. I'll let his old words try to convince people: >From bbn.com!bbn!mit-eddie!ll-xn!ames!umd5!mimsy!chris Thu Mar 10 15:37:10 EST 1988 Article 5474 of comp.lang.c: Path: bbn.com!bbn!mit-eddie!ll-xn!ames!umd5!mimsy!chris >From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.lang.c Subject: Why NULL is 0 Summary: you have seen this before, but this one is for reference Message-ID: <10576@mimsy.UUCP> Date: 9 Mar 88 02:26:10 GMT References: <2550049@hpisod2.HP.COM> <7412@brl-smoke.ARPA> <3351@chinet.UUCP> <10574@mimsy.UUCP> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 73 (You may wish to save this, keeping it handy to show to anyone who claims `#define NULL 0 is wrong, it should be #define NULL <xyzzy>'. I intend to do so, at any rate.) Let us begin by postulating the existence of a machine and a compiler for that machine. This machine, which I will call a `Prime', or sometimes `PR1ME', for obscure reasons such as the fact that it exists, has two kinds of pointers. `Character pointers', or objects of type (char *), are 48 bits wide. All other pointers, such as (int *) and (double *), are 32 bits wide. Now suppose we have the following C code: main() { f1(NULL); /* wrong */ f2(NULL); /* wrong */ exit(0); } f1(cp) char *cp; { if (cp != NULL) *cp = 'a'; } f2(dp) double *dp; { if (dp != NULL) *dp = 2.2; } There are two lines marked `wrong'. Now suppose we were to define NULL as 0. Clearly both calls are then wrong: both pass `(int)0', when the first should be a 48 bit (char *) nil pointer and the second a 32 bit (double *) nil pointer. Someone claims we can fix that by defining NULL as (char *)0. Suppose we do. Then the first call is correct, but the second now passes a 48 bit (char *) nil pointer instead of a 32 bit (double *) nil pointer. So much for that solution. Ah, I hear another. We should define NULL as (void *)0. Suppose we do. Then at least one call is not correct, because one should pass a 32 bit value and one a 48 bit value. If (void *) is 48 bits, the second is wrong; if it is 32 bits, the first is wrong. Obviously there is no solution. Or is there? Suppose we change the calls themselves, rather than the definition of NULL: main() { f1((char *)0); f2((double *)0); exit(0); } Now both calls are correct, because the first passes a 48 bit (char *) nil pointer, and the second a 32 bit (double *) nil pointer. And if we define NULL with #define NULL 0 we can then replace the two `0's with `NULL's: main() { f1((char *)NULL); f2((double *)NULL); exit(0); } The preprocessor changes both NULLs to 0s, and the code remains correct. On a machine such as the hypothetical `Prime', there is no single definition of NULL that will make uncasted, un-prototyped arguments correct in all cases. The C language provides a reasonable means of making the arguments correct, but it is not via `#define'. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out. ------- =_aaaaaaaaaa0 MIME-Version: 1.0 Content-Type: message/rfc822 >From henry@utzoo.uucp Wed Nov 8 05:35:40 1989 Relay-Version: version Notes 2.8.2 87/11/24; site hpausla.aso.hp.com From: henry@utzoo.uucp (Henry Spencer) Date: Tue, 7 Nov 1989 18:35:40 GMT Date-Received: Thu, 9 Nov 1989 06:24:45 GMT Subject: Re: NULL Message-ID: <1989Nov7.183540.2486@utzoo.uucp> Organization: U of Toronto Zoology Path: hpausla!hpcuhc!hpda!motcsd!apple!usc!cs.utexas.edu!wuarchive!mailrus!jarvis.csri.toronto.edu!utgpu!utzoo!henry Newsgroups: comp.os.minix References: <4455@ast.cs.vu.nl> <2144@prune.bbn.com> Lines: 30 In article <2144@prune.bbn.com> rsalz@bbn.com (Rich Salz) writes: >I believe that if you have anything other than "#define NULL 0" you >are encouraging sloppy non-portable code... Unfortunately, there is a lot of sloppy non-portable code out there already, and it is desirable to minimize code breakage where possible. This is why ANSI C allows NULL to be any integer constant expression equal to zero (e.g. `0' or `0L') or the same cast to `void *' (e.g. `((void *)0)': so that you can pick one that is the same size as the pointers on your machine, to minimize breakage of badly-written code. (The rationale for allowing the `void *' cast is that there may not be an integer type the same size as the pointers.) Of course, if different pointers are different sizes, or the representation of null pointers is strange, you are well and truly up the creek and there is *no* definition that will avoid breakage. Note that casting the zero to any *other* pointer type is illegal and pointless. (Although all manner of fudging may be necessary in the presence of non-ANSI compilers.) In any case, this stuff is a concession to badly-written code. No properly-written code under ANSI compilers will notice the difference between the different forms of NULL. In contexts where the desired type is not known from context -- basically, function arguments in the absence of a prototype or the presence of varargs -- NULL *must* be cast to the proper pointer type. Lazy programmers keep looking for a way around this, but there simply *isn't any*. -- A bit of tolerance is worth a | Henry Spencer at U of Toronto Zoology megabyte of flaming. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu ------- =_aaaaaaaaaa0--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199702142317.KAA12738>