26
int* p = 0;
int* q = &*p;

Is this undefined behavior or not? I browsed some related questions, but this specific aspect didn't show up.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • duplicate: http://stackoverflow.com/questions/2894891/this-code-appears-to-achieve-the-return-of-a-null-reference-in-c – Naveen May 24 '10 at 11:48
  • 5
    @Naveen There are no references in my program...? – fredoverflow May 24 '10 at 11:50
  • @FredOverflow: As far I see both are doing same thing, dereferencing a null pointer which invokes undefined behavior. – Naveen May 24 '10 at 12:21
  • possible duplicate of [Dereferencing the null pointer](http://stackoverflow.com/questions/2511921/dereferencing-the-null-pointer) – Kirill V. Lyadvinsky May 24 '10 at 12:42
  • 3
    This is not really a duplicate of either of those questions. The question "This code appears to achieve the return of a null reference in C++" asks about C++-specific semantics (while this question asks about both C and C++) and doesn't actually ask whether dereferencing the null pointer results in undefined behavior. The question "Dereferencing the null pointer," despite its title, is actually asking "what is the null pointer?" and not "is it undefined to dereference it?" – James McNellis May 24 '10 at 12:53
  • I changed its title to be more in line with its content. – Johannes Schaub - litb May 24 '10 at 13:40
  • Maybe we should simply retire the word 'dereference'. The more I understand these issues, the more I become convinved the word is just a little too ambiguous. Does it appear in the standard? – Aaron McDaid Apr 13 '15 at 23:53
  • And also, which of these three (if any) can be called 'dereferencing' (assuming 'dereference' is even defined clearly in the standard)? (1) `int* q = &*p;` (2) `int r = *p;` (3) `*p = 7;` – Aaron McDaid Apr 13 '15 at 23:55

4 Answers4

53

The answer to this question is: it depends which language standard you are following :-).

In C90 and C++, this is not valid because you perform indirection on the null pointer (by doing *p), and doing so results in undefined behavior.

However, in C99, this is valid, well-formed, and well-defined. In C99, if the operand of the unary-& was obtained as the result of applying the unary-* or by performing subscripting ([]), then neither the & nor the * or [] is applied. For example:

int* p = 0;
int* q = &*p; // In C99, this is equivalent to int* q = p;

Likewise,

int* p = 0;
int* q = &p[0]; // In C99, this is equivalent to int* q = p + 0;

From C99 §6.5.3.2/3:

If the operand [of the unary & operator] is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue.

Similarly, if the operand is the result of a [] operator, neither the & operator nor the unary * that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a + operator.

(and its footnote, #84):

Thus, &*E is equivalent to E (even if E is a null pointer)

Community
  • 1
  • 1
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • +1. What i was going to add as a comment to another answer in a hurry, until i saw this answer :) – Johannes Schaub - litb May 24 '10 at 12:40
  • I'll also note that it may not be the intent in C++ that performing indirection on a null pointer results in undefined behavior (per [CWG defect 232](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232)). However, the proposed resolution to that defect was _not_ incorporated into the C++0x final committee draft, so it's unlikely to be fixed before the next C++ standard is published. – James McNellis May 24 '10 at 14:04
  • I believe that in C++ this is also valid. As the unary * operator creates a reference (an alias to an object) so no de-referencing is happening. Then the & operator applied to a reference returns the NULL pointer again. See section 5.3.1-1 – Martin York May 24 '10 at 17:43
  • 1
    @Martin well we have proven you in another answer somewhere around last year that your interpretation of what "derereference" means is wrong. Applying unary `*` to a pointer dereferences, whether or not the lvalue to rvalue conversion is done is irrelevant. Edit: Please see the comment thread of this answer: http://stackoverflow.com/questions/988158/take-the-address-of-a-one-past-the-end-array-element-via-subscript-legal-by-the/988220#988220 – Johannes Schaub - litb May 24 '10 at 18:16
  • 2
    In particular notice the wording of `3.8/5` which says "Such a pointer may be dereferenced but the resulting lvalue may only be used in limited ways, as described below." and the various notes that make clear that "dereference" applies to transforming an address to an lvalue. The other action, transforming an lvalue to an rvalue, is not called dereference, but it's called lvalue-to-rvalue conversion or simply "accessing the stored value" (as in 3.10/15) etc. – Johannes Schaub - litb May 24 '10 at 18:24
3

Yes that would be undefined behavior, but your compiler might optimize the &* out.

Why it its undefined, is that you are attempting to access memory outside your addressable space.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
-1

Yes, dereferencing the null pointer is undefined behavior. Integer constant 0 in a pointer context is the null pointer. That's it.

Now, if your second line was int *q = p; that would be a simple pointer assignment. If the compiler removes the &* and reduces the dereference to an assignment, you're OK.

mpez0
  • 2,815
  • 17
  • 12
  • 4
    But it's still undefined. Just because a particular version of a particular compiler with a particular optimization level handles this doesn't mean "you're OK" - because it's undefined, it could stop working in the next release of the compiler, if the optimization level changes (or in months ending with 'R'). – David Gelhar May 24 '10 at 11:57
-1

IMHO, As far as the two code lines are concerned, there isn't any access outside the address space. The second statement is simply taking the address of (*p) which would be 'p' again and hence it will store '0'. But the location is never accessed.

Salil
  • 88
  • 9