Date: 19 Jan 1998 15:39:35 +0100 From: dag-erli@ifi.uio.no (Dag-Erling Coidan Smørgrav) To: Terry Lambert <tlambert@primenet.com> Cc: asami@cs.berkeley.edu (Satoshi Asami), jamie@itribe.net, jdevale@ece.cmu.edu, hackers@FreeBSD.ORG Subject: Re: FreeBSD Netcards Message-ID: <xzp7m7wr0ig.fsf@hel.ifi.uio.no> In-Reply-To: Terry Lambert's message of "Mon, 12 Jan 1998 18:19:47 %2B0000 (GMT)" References: <199801121819.LAA24153@usr04.primenet.com>
next in thread | previous in thread | raw e-mail | index | archive | help
Terry Lambert <tlambert@primenet.com> writes: > If you: > > #include <stdio.h> > > main() > { > char c = NULL; > > printf( "The value of a NULL character is %d\n", c); > > exit( 0); > } > > The program, when compiled, does not bitch about the "loss of precision" > in the assignment in the declaration of 'c'. 8-). > > The program, when run, displays: > > The value of a NULL character is 0 > > I'd say the compiler says that 'c' is a "NULL character", until it > bitches, properly, about the assignment. Ahem. Sorry for following up on a week-old article, but there's something that needs straightening out here. NULL is a macro that expands to 0. Some compiler vendors define it to (void *)0 or whatever, which is useful in some cases, such as the execl(2) functions, but mostly makes no difference. Now the crux of the matter is that the ISO C standard states that 0 is not only an integer literal, but also a pointer literal (or rather *the* pointer literal, as all other literals need a cast to be used as pointers) which translates into a bit pattern which is guaranteed not to be a valid pointer on whichever platform you're working on. This is why NULL expands to 0: because 0, when assigned to a pointer, means NULL. Even if the NULL pointer, on your particular platform, is not all bits zero, the literal 0 will translate to the NULL pointer. Naturally, having the NULL pointer all bits zero (as it is on the i386, and most modern architectures such as the motorola 68K, the MIPS RISC or the Sun Sparc / UltraSparc) is very useful since global static data is initialized to all bits zero upon startup, so global static pointers are initialized to NULL. Back to execl(2): this class of functions use varargs and expect their argument lists to be terminated by a NULL pointer. Now, on a two's complement platform with pointers and integers of the same size and an all bits zero NULL pointer (i.e. any sane modern architecture) it doesn't make a difference if the compiler thinks you're passing the integer 0 or the NULL pointer, as their memory representation is identical. However, on platforms where the NULL pointer is not all bits zero, or where pointers are of a different size from integers, the difference between the NULL pointer and the integer 0 is no longer academic, and passing the integer 0 to execl(2) instead of a NULL pointer can lead to unpleasant results. Finding the euphemism in the previous sentence is left as an exercise to the reader. On those platforms (which are more common than you might think - take the huge memory model on an 80x86 in real mode, which has 16-bit integers but 32-bit pointers) it is useful to have NULL expand to (void *)0, as this will force the compiler to interpret NULL as a pointer rather than an integer. Therefore, it is *perfectly correct* for the compiler to produce code that outputs "The value of a NULL character is 0" from the source code you give, since what you wrote is, in effect, char c = 0; There is no loss of precision in the assignment, since you are assigning a literal that fits well within 8 bits to an 8-bit signed char. There is no type conversion needed. There is nothing fishy whatsoever about the compiler's behaviour. If you're not convinced, compile the source code with the -E switch (I assume you're using gcc) which will dump the preprocessor output to stdout. You will see that NULL expanded to 0. If you're still not convinced, feel free to consult /usr/include/stdlib.h, the White Book, or, for that matter, the text of the ISO C standard. You also wrote the following > Also, you're right that the standard allows for a non-zero value > for NULL. I don't know of anyone who uses this; it's pretty much > in there to cause problems, like a lot of other "features", ie: the > assumption that certain optimizations are allowable unless they are > explicitly disallowed, etc.. The standard does *not* allow for a non-zero value of NULL. The standard very clearly states that the literal 0, when assigned to a pointer variable, evaluates to a NULL pointer. The standard does not, however, say anything about the internal representation of a NULL pointer. Wether or not a NULL pointer is all bits zero is implementation-defined. > So pretty much until you fix the compiler, I'm going to keep my > terminology as fuzzy as the compiler's enforcement. Again, nothing is wrong with the compiler. It's in perfect accordance with the ISO C standard. Your use of NULL in "a NULL string" or "the NULL character", however, is definitely incorrect. Instead, you should use "an empty string" and "the NUL character" (only one L), respectively. Hope this cleared up what I consider a rather fundamental misunder- standing of C pointer mechanics. -- * Finrod (INTJ) * Unix weenie * dag-erli@ifi.uio.no * cellular +47-92835919 * RFC1123: "Be liberal in what you accept, and conservative in what you send"
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?xzp7m7wr0ig.fsf>