Well, you obviously know more about it than I do. And yes, foo = 0 might set foo to 0x7fffffff is certainly astonishing.
But I get your point. (And yes, I programmed on the Intel 8085, and 8086, and Zylog Z80 (the first Z processor!) and I remember that goofy 20-bit segment + offset.) What about char *foo = 0; if ( foo ) ... ; Would that then evaluate as true or false? Must be false; otherwise all those if ( ! f = fopen() ) would fail. But false is a little counterintuitive also. Could not the Z (our Z!) implementation of C used something like 7FFFF000 for NULL and thereby trapped the dereferencing of NULL? (And yes, some provision would have had to be made for the PSA.) Charles -----Original Message----- From: IBM Mainframe Assembler List [mailto:[email protected]] On Behalf Of Bob Raicer Sent: Friday, September 11, 2020 4:19 PM To: [email protected] Subject: Re: Deep Cuts On Wed, 9 Sep 2020 13:17:24 -0700 Charles Mills wrote: > Doesn't that say "0 is never a valid address"? Or at least "zero > never compares equal to the address of any actual object"? "0 is > never equal to any valid address"? Seems about the same to me. No, it doesn't say "0 is never a valid address". It says that the constant expression value of zero when used as an assignment to a pointer variable is semantically recognized as meaning assigning an implementation defined value to that pointer. This implementation defined value can be thought of as a "special" address value which satisfies the requirement that it "is guaranteed to compare unequal to a pointer to any object or function." That dereferencing it may cause some form of an exception (absolutely machine and/or implementation dependent) may be an added bonus; it is not required by the standard and the standard simply states that the behavior is undefined. So, if some implementation defined this value as perhaps 0x7FFFFFFF, then the assignment: char *somepointer = 0; would set somepointer to 0x7FFFFFFF (assuming a pointer to char is 4-bytes in length). Similarly, a statement like this: if (0 == somepointer) ... would cause a comparison to the value 0x7FFFFFFF, not zero. The special treatment of the constant expression of zero in these contexts is quirky and a source of great confusion. This comp.lang.c FAQ aims to clarify the confusion: URL: http://c-faq.com/null/machnon0.html comp.lang.c FAQ list ยท Question 5.5 Q: How should NULL be defined on a machine which uses a nonzero bit pattern as the internal representation of a null pointer? A: The same as on any other machine: as 0 (or some version of 0; see question 5.4). Whenever a programmer requests a null pointer, either by writing "0" or "NULL", it is the compiler's responsibility to generate whatever bit pattern the machine uses for that null pointer. (Again, the compiler can tell that an unadorned 0 requests a null pointer when the 0 is in a pointer context; see question 5.2.) Therefore, #defining NULL as 0 on a machine for which internal null pointers are nonzero is as valid as on any other: the compiler must always be able to generate the machine's correct null pointers in response to unadorned 0's seen in pointer contexts. A constant 0 is a null pointer constant; NULL is just a convenient name for it (see also question 5.13). (Section 4.1.5 of the C Standard states that NULL "expands to an implementation-defined null pointer constant," which means that the implementation gets to choose which form of 0 to use and whether to use a void * cast; see questions 5.6 and 5.7. "Implementation-defined" here does not mean that NULL might be #defined to match some implementation-specific nonzero internal null pointer value.) Going back to the old Intel 808x real mode memory addressing model, a pointer in C could be represented as a 16-bit (unsigned) integer. The effective address was arrived at by the processor by left shifting by 4-bits the value contained in a segment register and then adding the 16-bit "address" (i.e., an offset) value. So it was perfectly permissible to have some C pointer contain the value zero if the item being pointed to was at offset zero from the value contained in the segment register. C.A.R. Hoare apologized for the invention of the null reference. The quote that I found on Wikipedia is shown below: "I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years." I have worked as a software developer on a hardware platform where the hardware actually recognized a "special" address value (which was not zero) as being always invalid and this value was the implementation defined value of the null pointer. A zero pointer value, while a little awkward to generate, was totally valid. In my view, C was developed as a somewhat high level programming language which still allowed relatively easy and run-time efficient access to lower level machine facilities. Source code portability was a goal, however, this goal was not intended to severely limit the programmer; implementation and platform dependencies are discouraged, but not disallowed. That's not to say that organizations might not have more stringent requirements in that regard (which was one of the motivations for the creation of programs like "lint"). Bob
