Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!rutgers!sri-spam!ames!oliveb!sun!gorodish!guy From: guy%gorodish@Sun.COM (Guy Harris) Newsgroups: comp.lang.c Subject: Re: Writing readable code Message-ID: <22641@sun.uucp> Date: Fri, 3-Jul-87 07:09:33 EDT Article-I.D.: sun.22641 Posted: Fri Jul 3 07:09:33 1987 Date-Received: Sat, 4-Jul-87 13:17:26 EDT References: <1158@copper.TEK.COM> <6858@auspyr.UUCP> <17171@cca.CCA.COM> <926@argus.UUCP> Sender: news@sun.uucp Lines: 66 > It's not mnemonic, on some machines its just wrong. NULL is ***NOT*** > defined as zero on all machines. There does not exist, and will never exist, a machine for which a legitimate C compiler will produce different code for: char *p; if (p == 0) and char *p; if (p == NULL) if NULL is defined as 0 - just 0, nothing else. The same is true for char *p; p = 0; and char *p; p = NULL; (If anybody cares to challenge this statement, I will point out that all such challenges in the past have been refuted. There are passages in K&R and in the ANSI C draft that make it abundantly clear that the compiler must do the right thing both for "if (p == 0)" and "p = 0"; for example, if you have 16-bit "int"s and 32-bit pointers, the compiler must not generate a 16-bit assignment or a 16-bit comparison. If this seems counter-intuitive to anybody, replace "char *p" with "long p", and note that the compiler obviously should not generate 16-bit assignments or comparisons in those cases. A pointer is no different here.) Neither pointer assignment nor pointer comparison, then, requires any decoration to be wrapped around 0 to make them work. The only case where you have to wrap decoration around 0 to make it work is when you are passing null pointers as arguments to procedures. In the general case, there is no magic goop that you can wrap around *all* instances of 0 used as null pointers that will make it work for all those instances. For instance, you might have a word-addressible 16-bit machine, where character pointers require 32 bits. In this case, passing "(char *)0" to a procedure might be done by passing 32 bits of zero, and passing "(int *)0" might be done by passing 16 bits of zero. As such, the only correct way to handle this is to cast all occurrences of 0 or NULL to a pointer of the appropriate type when passing them as procedure arguments. (If you don't, and you have a type-checker like "lint", if it's any good it will complain about code that doesn't properly cast the pointers.) Some vendors offering C implementations on machines where all pointers are the same length, and all null pointers have the same bit pattern, cheat by defining NULL as 0L or (char *)0. This makes the code work - *on that particular machine* - but doesn't make it correct, in the sense that it will work correctly on any correct C implementation. (It also won't silence a good type-checker. In fact, the "NULL is (char *)0" trick would NOT silence complaints from a type-checker if you write code that does the casting properly, whereas leaving NULL as 0 would do so.) Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com