(uintptr_t) NULL

L

Lauri Alanko

Is ((uintptr_t) NULL) guaranteed to be converted into a null pointer
when cast into void*? At first glance one would think so, but to my
understanding NULL might be defined as 0, and there is no guarantee
that a null pointer gets converted into an integer 0 when cast to
uintptr_t.

So one needs to explicitly use ((uintptr_t) (void*) 0) which seems a
bit clunky. Is my reasoning correct?

Also, what's the reason that NULL is allowed to be a plain integer
constant instead of an expression with a pointer type? I can't see any
benefit from it, and it leads to confusion in rare corner cases such
as this one.

Thanks,


Lauri
 
L

Lauri Alanko

((uintptr_t) NULL is already a null pointer.

N869
6.3.2.3 Pointers
[#3]
If a null pointer constant is
converted to a pointer type, the resulting pointer, called a
null pointer, is guaranteed to compare unequal to a pointer
to any object or function.

How is this relevant? uintptr_t is an integer type, not a pointer
type.


Lauri
 
B

Ben Pfaff

pete said:
I would say yes.
If NULL is defined as 0, then ((uintptr_t) 0)
is an integer constant expression with the value 0.

I agree that (void *) ((uintptr_t) 0) is a null pointer.

But the question sounds ambiguous to me. In the code below, 'x'
has the value of (uintptr_t) 0, but I don't think that 'p' is
guaranteed to be a null pointer, because 'x' is not a null
pointer constant.

const uintptr_t x = (uintptr_t) 0;
void *p = (void *) x;
 
E

Eric Sosman

Any null pointer, when converted to an integral type, produces a value
of zero.
Any integer with a value of zero, when converted to a pointer type,
produces a null pointer.

Christian, can you provide a reference to some part of the
Standard that guarantees this? 6.3.2.3p3 says we may convert a
zero-valued integer *constant* expression to a null pointer, but
says nothing about non-constant expressions, or about conversion
from pointer to integer. (In fact, 6.3.2.3p5-6 say both kinds of
conversion are implementation-defined, or even undefined in some
circumstances.)

7.18.1.4 says any valid void* can be converted to intptr_t
and back without damage (if the types exist; they're optional),
but doesn't say anything about the mapping beyond the fact that it's
reversible. (It's also not clear whether a null pointer has a "valid"
value for the purposes of this conversion; 7.1.4p1 calls a null pointer
"invalid" as an argument for some library functions and a footnote to
6.5.3.2p4 calls it "invalid" for dereferencing, but I can't find any
description of what's valid and invalid for conversion.)
NULL is a null pointer constant, and a null pointer constant is either
an integer with a value of 0 or such an integer cast to void* and
therefore a null pointer. In either case, (uintptr_t) NULL has a value
of zero. And that cast to void* yields a null pointer.

I'm in complete agreement with the first sentence, but I can't
find Standard support for the second and third.
 
J

James Kuyper

Any null pointer, when converted to an integral type, produces a value
of zero.

Citation, please? I know of no such requirement.
Any integer with a value of zero, when converted to a pointer type,
produces a null pointer.

That is true when you're referring to an integer constant expression
with a value of zero, because such an expression qualifies as a null
pointer constant. This is NOT the case for integer expressions with a
value of zero that do not qualify as integer constant expressions. In
particular:

int i = 0;
int *p = (int*)i;

In the above code, p is not guaranteed to be a null pointer, though
there's a lot of systems where that would happen to be the case.
NULL is a null pointer constant, and a null pointer constant is either
an integer with a value of 0 or such an integer cast to void* and
therefore a null pointer. In either case, (uintptr_t) NULL has a value
of zero. And that cast to void* yields a null pointer.

If NULL expands to

(void*)0

Then (uintptr_t)NULL will expand to

(uintptr_t)(void*)0

Section 7.18.1.4 guarantees that the result of converting this
expression back to (void*) produces a result that compares equal to
(void*)0. Since null pointers can compare equal only to other null
pointers, your final conclusion is correct. However, your intermediate
step is incorrect; there's nothing that guarantees that

(uintptr_t)(void*)0 == 0

It might be some entirely different integer value that ALSO converts to
a null pointer.
 
K

Keith Thompson

christian.bau said:
Any null pointer, when converted to an integral type, produces a value
of zero.

That's commonly true for most implementations, but I don't think the
standard supports it.
Any integer with a value of zero, when converted to a pointer type,
produces a null pointer.

Likewise. The standard's only guarantee in this area is that an integer
*constant expression*, when converted to a pointer type, yields a null
pointer value.
NULL is a null pointer constant, and a null pointer constant is either
an integer with a value of 0 or such an integer cast to void* and

No, an integer *constant expression* with a value of 0.
therefore a null pointer. In either case, (uintptr_t) NULL has a value
of zero. And that cast to void* yields a null pointer.

Consider a hypothetical implementation with the following
characteristics:

For simplicity, assume int and all pointer types are 4 bytes, or 32
bits.

The internal representation of a null pointer is all-bits-1
(0xffffffff).

Except where otherwise required by the standard, all int-to-pointer,
pointer-to-int, and pointer-to-pointer conversions simply copy the bits.

For this implementation, this:
void *p = (void*)0;
set p to a null pointer (representation 0xfffffff), but this:
int zero = 0;
void *q = (void*)zero;
sets q to a non-null pointer (representation 0x00000000).

It's admittedly counterintuitive that conversions from int to void*
*of the same int value* yield different results, just because one
is expressed as an integer constant expression and the other isn't.
But the implementation is conforming, and it doesn't satisfy your
assumptions.

If it were the intent that *any* conversion of a 0 integer
value to a pointer type yields a null pointer, then 6.3.2.3p3
could easily have said so. The fact that it's specifically
limited to integer constant expressions is not accidental.
 
E

Eric Sosman

Being a "null pointer constant" is just syntax. For example, 0 is a
"null pointer constant", but (int) 0, which is exactly the same type
and value, is not. Conversion from integer to pointer, however,
converts values, independent of their form. So any int with a value of
0 is converted to the same pointer. If the int has the special form of
a null pointer constant, the result is guaranteed to be a null
pointer. But because the conversion is independent of that special
form, _any_ int with a value 0 converted to a pointer produces a null
pointer.

Again I ask: Chapter and verse? Anything at all to amplify or
override the explicit and normative "it's implementation-defined"
language in 6.3.2.3p5-6? Anything?
 
K

Keith Thompson

christian.bau said:
Being a "null pointer constant" is just syntax. For example, 0 is a
"null pointer constant", but (int) 0, which is exactly the same type
and value, is not.
Right.

Conversion from integer to pointer, however,
converts values, independent of their form.

That's where I disagree.
So any int with a value of
0 is converted to the same pointer. If the int has the special form of
a null pointer constant, the result is guaranteed to be a null
pointer. But because the conversion is independent of that special
form, _any_ int with a value 0 converted to a pointer produces a null
pointer.

If the conversion were independent of the form of the operand, then
I suggest that C99 6.3.2.3p3 would simply say that converting an
integer value 0 to a pointer type yields a null pointer. See also
my other followup.

[...]
 
B

Ben Bacarisse

christian.bau said:
Being a "null pointer constant" is just syntax. For example, 0 is a
"null pointer constant", but (int) 0, which is exactly the same type
and value, is not.

Why do you say (int)0 is not a null pointer constant? It meets all the
requirements that I can find.

<snip>
 
T

Tim Rentsch

pete said:
[snip]

If NULL is ((void *)0) then
(void *)((uintptr_t) NULL)
is still a null pointer constant.

Still a null pointer; not necessarily a null pointer constant.
 
T

Tim Rentsch

christian.bau said:
Any null pointer, when converted to an integral type, produces a value
of zero.

The Standard does not guarantee this. In fact the Standard does
not guarantee that converting a pointer to any integer type
(other than _Bool) even has defined behavior. 6.3.2.3p6.
Any integer with a value of zero, when converted to a pointer type,
produces a null pointer.

The Standard does not guarantee this either. The only guarantee
made for integer-to-pointer conversion is for null pointer
constants; if such a to-be-converted expression isn't a null
pointer constant, all bets are off. 6.3.2.3p5, 6.3.2.3p3.

(There are additional guarantees if intptr_t is defined,
but those don't say anything about converting a value of zero.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top