13

The standard says that dereferencing the null pointer leads to undefined behaviour. But what is "the null pointer"? In the following code, what we call "the null pointer":

struct X
{
  static X* get() { return reinterpret_cast<X*>(1); }
  void f() { }
};

int main()
{
  X* x = 0;
  (*x).f(); // the null pointer?  (1)

  x = X::get();
  (*x).f(); // the null pointer?  (2)

  x = reinterpret_cast<X*>( X::get() - X::get() );
  (*x).f(); // the null pointer?  (3)

  (*(X*)0).f(); // I think that this the only null pointer here (4)
}

My thought is that dereferencing of the null pointer takes place only in the last case. Am I right? Is there difference between compile time null pointers and runtime according to C++ Standard?

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
big-z
  • 6,812
  • 5
  • 20
  • 19
  • That's not a homework. The C++ Standard says not much about dereferencing the null pointers. I just want to know. – big-z Mar 24 '10 at 22:41
  • The first part of my answer here talks about dereferencing null pointers: http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in-undefined-behav (I love that question.) – GManNickG Mar 24 '10 at 22:43

4 Answers4

12

Only the first and the last are null pointers. The others are results of reinterpret_cast and thus operate on implementation defined pointer values. Whether the behavior is undefined for them depends on whether there is an object at the address you casted to.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • What is the difference between dereferencing the null pointer and some invalid pointer? – big-z Mar 24 '10 at 22:45
  • @Johannes : they are null pointers, but will they cause a core dump? Initially I thought so, but after some thought I'm not so sure. See my answer above. – Scott Smith Mar 24 '10 at 22:45
  • 2
    @Scott Smith: It's implementation defined. Particularly on platforms which have no concept of a "core" i.e. anything outside of UNIX. – Billy ONeal Mar 25 '10 at 02:54
12

An integer constant expression that evaluates to 0 is valid as a null pointer, so the first case is also dereferencing a null pointer.

A pointer which is set to 0 via some arithmetic calculation is not necessarily a null pointer. In most implementations it will behave in the same way as a null pointer, but this is not guaranteed by the standard.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 1
    "Converting an integral constant expression (5.19) with value zero always yields a null pointer (4.10), but converting other expressions that happen to have value zero need not yield a null pointer" (5.2.10/5 note 64). – James McNellis Mar 24 '10 at 23:12
  • 2
    @James Ahh! So 0!=NULL for very large values of 0! – Earlz Mar 24 '10 at 23:22
  • Notice the difference between 0 and a null pointer. `0` is not valid as a null pointer always, but only when the conversion to a null pointer is possible. `0` is a null pointer constant and only where the conversion to a null pointer is considered, it is valid as a null pointer by that conversion. @Kirill refers to the internal representation of that null pointer, while i believe @Mark is referring to something completely else (to the value of a null pointer constant, which in fact always and necessarily has the value `0`). – Johannes Schaub - litb Mar 25 '10 at 09:06
7

C++ Standard (2003) 4.10

4.10 Pointer conversions

1 A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4).

5.2.10 Reinterpret cast

Note 64) Converting an integral constant expression (5.19) with value zero always yields a null pointer (4.10), but converting other expressions that happen to have value zero need not yield a null pointer.

1) X* x = 0; (*x).f(); Yes. 0 is integral constant expression and is converted to the null pointer constant. Then null pointer constant can be converted to the null pointer value.

2) x = X::get(); no, see note 64 in 5.2.10

3) x = reinterpret_cast<X*>( X::get() - X::get() ); no, see note 64 in 5.2.10

4) ((X)0).f(); Yes. 0 (integral constant expression) --> the null pointer constant --> the null pointer value.

Alexey Malistov
  • 26,407
  • 13
  • 68
  • 88
0
X* x = 0;
(*x).f(); // the null pointer?  (1)

I think this qualifies as dereference, even though f() never actually uses the this pointer, and there are no virtual methods in X. My reflex was to say that this is a crash, but now that I think of it, I'm not so sure.

x = X::get();
(*x).f(); // the null pointer?  (2)

Probably an invalid pointer. not sure whether it will crash (see above for reasoning).

x = reinterpret_cast<X*>( X::get() - X::get() );
(*x).f(); // the null pointer?  (3)

Does the expression X::get() - X::get() compile? I didn't think it was legal to subtract a pointer from another pointer like that.

EDIT: D'oh! Of course it's legal. What was I thinking? Clearly, I am a maroon.

Scott Smith
  • 3,900
  • 2
  • 31
  • 63
  • In concerns to calling a nonstatic function on a null instance: It leads to undefined behavior. So all bets are off, clearly. That said, in practice as long as there is no need for the `this` pointer (no virtual functions, no members, etc.), then it won't crash, since it's never used. – GManNickG Mar 24 '10 at 22:48
  • subtracting pointers is very common - and it will return the difference between the two pointers. However since these are not in the same array then you are right - result undefined. (but it probably compiles) – pm100 Mar 24 '10 at 22:55
  • @Scott Smith, I just compiled that in GNU C++ and executed without errors. Why do you think that subtracting pointers is illegal? My first thought was that code in OP question will crash in (2). – Kirill V. Lyadvinsky Mar 24 '10 at 22:56
  • @Kirill: Pointer subtraction is explicitly undefined behavior if both pointers do not point to elements in the same array (or one past the end of said array.) It's in 5.7/6. That said, you can cast a pointer to a `uintptr_t` or kin, and compare those, yielding an integer value. – GManNickG Mar 24 '10 at 23:03
  • Adding two pointers is not allowed; subtracting one pointer from another is. However, the result of the subtraction is not a pointer; it's an integer value with type `ptrdiff_t`. – James McNellis Mar 24 '10 at 23:04
  • @GMan, I was talking about exact implementation (g++ 4.x.x). Dereferencing null pointer is a common hack in C sources in Linux as I can see, hence same code should work in C++ for back compatibility. But I thought that dereferencing invalid pointer will lead to core dump. – Kirill V. Lyadvinsky Mar 24 '10 at 23:09
  • @pm100 - Ah, silly me, of course. I've done this before - dunno what I was thinking. – Scott Smith Mar 25 '10 at 00:55