TITLE: a potpourri of NULL --- Article 1/2 -------------------------------------------------------- (Newsgroups: comp.lang.c++) HARRY: harry@elfuerte.fipnet.fi (Harri Pesonen) |> >I found two interesting things in the book C++ Tutorial by Microsoft. |> >Page 65: |> >"If new cannot allocate the memory requested, it returns 0. In C++, |> >a null pointer has the value 0 instead of the value NULL." |> >I have always used 0 as a null pointer even in C, and I never understood |> >why NULL was even invented. ROBERT: rmartin@rcmcon.com (Robert Martin) |> Back in the early days of C it was assumed that the size of a pointer |> was the same as the size of an int. Thus, 0 was used as the "null" |> pointer. And stdio.h (or some other standard header) declared the |> macro NULL to be 0. JAMES: kanze@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763), 4 May 96 Not quite true. At least according to Kernighan and Richie, NULL was introduced for clarity, i.e.: the authors of C prefered to write NULL instead of 0 when a pointer was meant. ROBERT: |> Later, segmented architectures were invented by some "genius" and |> other strange address conventions were encountered such that integers |> and pointers were not the same size. JAMES: *And* not all pointers are the same size, either. I might add that you don't need segmented architecture for pointers and int's to have a different size. ROBERT: |> Consider the following function in C: |> f(p) |> int *p; |> { |> if (p) *p = 0; // clear out the int. |> } |> Now consider what would happen if you called it like so: |> f(0); JAMES: According to the ISO standard (today), undefined behavior. This expression creates an *implicite* declaration: int f( int ) ; Note that if you later use the function correctly, an ISO conformant C compiler should declare an error. ROBERT: |> If an int and a pointer are not the same size, then this call will |> crash since in C 0 is an int. JAMES: And even if they are the same size, you still have undefined behavior. (According to the standard; most implementations will give you a warning, and generate code which works.) ROBERT: |> Thus, NULL was redefined to ((char*)0) and later ((void*)0) JAMES: Which doesn't help at all in the above example. Since there is no guarantee that a pointer to int is the same size as a pointer to void or char. (Void* and char* are guaranteed to be the same size.) It will work on 80x86, however:-). ROBERT: |> In C++ however, the compiler always know the type of the argument to a |> function (except in the ... case where the same problem still exists!) |> So 0 can be used to represent a null pointer. In fact, 0 is a |> special constant whose type must be derived from context. JAMES: Almost. The exact words are: "A constant expression rvalue of an integer type that evaluates to zero (called a null pointer constant) can be converted to a pointer type." Not will be, can be. At each place where the conversion takes place, the standard specifies it. Thus, in section 5.17 (Assignment operators): "If the left operand is not of class type, the expression is converted to the unqualified type of the left operand using standard conversions and/or user-defined conversions." There are detectable differences: 1. Function overloading: void f( int ) ; void f( void* ) ; f( 0 ) calls f( int ). There is no ambiguity. (On the other hand, with: void f( long ) ; void f( void* ) ; there is ambiguity, since both calls require an implicit conversion.) 2. sizeof( 0 ) == sizeof( int ), regardless of the size of pointers. Ditto typeid. There are probably a few others. HARRY: |> >Page 65: |> >"You can, however, delete a null pointer (a pointer with value 0) without |> >any adverse effects." |> >This, too, makes sense, and I thought that this is true, but then I noticed |> >that Borland C++ 4.5 crashes with 'delete 0'. So, where is the bug? JAMES: The exact statement (from the working papers) is: "if the value of the operand of delete is the null pointer, the operation has no effect." There is *no* statment suggesting implicit conversion of 0 to a pointer. If you think about it, it could hardly be otherwise. The conversion must convert to a pointer of a specific type. (There is no abstract pointer type, only void*, int*, etc.) What type should be used here? --- Article 2/2 -------------------------------------------------------- (Newsgroups: comp.lang.c++.moderated) ART: artyom@kansmen.com (Art Shelest) >>Base* pb = new Derived; > >>if new returns NULL, is it possible for pb to get non-zero expression because >>of the offset in derived class? > IGOR: igor%@connect.com.au >[ ... example snipped ... ] > >I wouldn't have thought you could get a non-zero expression. I thought that >the standard demands that NULL be treated explicitly as zero no matter what >sort of casting you do to it. STEVE: clamage@Eng.Sun.COM (Steve Clamage), 13 Jun 96 The question (and the answer above) are not well-formed. The language rules require that a null pointer cast to any pointer type still be a null pointer. The requirements on a null pointer are that any two null pointers of the same type compare equal, and compare unequal to every pointer of that type that actually points to an object (or function). Neither C nor C++ places any requirements on how a null pointer is represented. It might be represented as all-bits-zero, but that is not a requirement, and indeed some systems historically have used non-zero null pointer representations. I can imagine a computer architecture where pointers carried extra status bits, one of which might indicate "null pointer". The value of the pointer would then be irrelevent, as any pointer operation would check the "null" bit first (in the hardware). Typically null pointers are represented only as all-bits-zero, because that is usually the most convenient representation. In that case, the compiler must always test for null before performing any adjustment on a pointer value.