Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

NULL with representation other then all bits 0

4 views
Skip to first unread message

yossi....@gmail.com

unread,
Jan 28, 2006, 8:32:35 AM1/28/06
to
Hi!

There is a system where 0x0 is a valid address, but 0xffffffff isn't.
How can null pointers be treated by a compiler (besides the typical
"solution" of still using 0x0 for "null")?

- AFAIK C allows "null pointers" to be represented differently then
"all bits 0". Is this correct?
- AFAIK I can't `#define NULL 0x10000' since `void* p=0;' should work
just like `void* p=NULL'. Is this correct?
- AFAIK I can identify contexts where `0' is used as a pointer and use
the numeric value 0xffffffff rather then 0x0. Is this correct? In
particular, should `void* p;' initialize p to "null pointer" rather
then "zero" (so it has to be placed in ".data" rather then ".bss" in
terms of typical implementations if "null pointer" is not represented
as all bits 0)? Worse, should `memset(&p, 0, sizeof(void*))' set p to
the "null pointer" rather then "zero"? Should casts from int to void*
convert (int)0 (bits: 0x0) to (void*)0 (bits: 0xffffffff)?

I know that this topic has been discussed a lot. That's even one of the
reasons I'm not sure what the real answers are - I remember too many of
them and can't tell the right ones from the wrong ones...

Thanks in advance!
-- Yossi

Vladimir S. Oka

unread,
Jan 28, 2006, 8:48:49 AM1/28/06
to
yossi....@gmail.com wrote:

> Hi!
>
> There is a system where 0x0 is a valid address, but 0xffffffff isn't.
> How can null pointers be treated by a compiler (besides the typical
> "solution" of still using 0x0 for "null")?

Standard does not prescribe actual bit representation of a NULL pointer,
that is implementation dependent. However, the Standard does prescribe
that 0 used in a pointer context is a valid representation of a NULL
pointer (even if it's not all-bits-zero).

>
> - AFAIK C allows "null pointers" to be represented differently then
> "all bits 0". Is this correct?

Yes (see above).

> - AFAIK I can't `#define NULL 0x10000' since `void* p=0;' should work
> just like `void* p=NULL'. Is this correct?

Yes and no. Yes, if you're compiler writer, and on your implementation
NULL pointer representation is 0x10000, so you defined it thus in the
standard header files. No, if you're trying to re-define NULL in your
own C program. The part of your sentence after `since` is irrelevant in
this context (but true).

> - AFAIK I can identify contexts where `0' is used as a pointer and use
> the numeric value 0xffffffff rather then 0x0. Is this correct? In

Yes, but you'd have to cast it an appropriate pointer type. However,
this will make your program utterly non-portable, as the next
implementation you compile it on may have defined NULL as something
entirely different (bit-wise).

> particular, should `void* p;' initialize p to "null pointer" rather
> then "zero" (so it has to be placed in ".data" rather then ".bss" in
> terms of typical implementations if "null pointer" is not represented
> as all bits 0)? Worse, should `memset(&p, 0, sizeof(void*))' set p to
> the "null pointer" rather then "zero"? Should casts from int to void*
> convert (int)0 (bits: 0x0) to (void*)0 (bits: 0xffffffff)?
>
> I know that this topic has been discussed a lot. That's even one of
> the reasons I'm not sure what the real answers are - I remember too
> many of them and can't tell the right ones from the wrong ones...

I suggest you carefully read the C FAQ at http://www.c-faq.com/,
especially Section 5 which is in its entirety devoted to NULL pointers,
and I believe answers all your questions (direct link is:
http://www.c-faq.com/null/index.html)

Cheers

Vladimir


--
A bachelor is a selfish, undeserving guy who has cheated some woman out
of a divorce.
-- Don Quinn

Flash Gordon

unread,
Jan 28, 2006, 9:42:35 AM1/28/06
to
Vladimir S. Oka wrote:
> yossi....@gmail.com wrote:

<snip stuff about null pointer representation being not all bits 0>

>> - AFAIK I can identify contexts where `0' is used as a pointer and use
>> the numeric value 0xffffffff rather then 0x0. Is this correct? In
>
> Yes, but you'd have to cast it an appropriate pointer type. However,
> this will make your program utterly non-portable, as the next
> implementation you compile it on may have defined NULL as something
> entirely different (bit-wise).

<snip>

Actually, even if that is the correct representation of a null pointer
the conversion might defined so that converting 0xffffffff actually
converts to address 0 since otherwise you would not be able to produce
an address 0.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.

Gordon Burditt

unread,
Jan 28, 2006, 12:52:12 PM1/28/06
to
>There is a system where 0x0 is a valid address, but 0xffffffff isn't.
>How can null pointers be treated by a compiler (besides the typical
>"solution" of still using 0x0 for "null")?
>
>- AFAIK C allows "null pointers" to be represented differently then
>"all bits 0". Is this correct?

Yes.

>- AFAIK I can't `#define NULL 0x10000' since `void* p=0;' should work
>just like `void* p=NULL'. Is this correct?

You, as programmer, are not allowed to do this.
You, as compiler implementor, are allowed to do this.

There is no prohibition of an implementation where "all pointers with
a prime-valued bit pattern are considered null pointers. This might
make the code generated for pointer comparison messy, since two null
pointers should compare equal to each other even if they don't have
the same bit representation.

>- AFAIK I can identify contexts where `0' is used as a pointer and use
>the numeric value 0xffffffff rather then 0x0. Is this correct? In

You can identify null pointer constants and use the correct bit
pattern (which is 0xdeadbeef, not 0xffffffff on 32-bit machines)
at compile time.

>particular, should `void* p;' initialize p to "null pointer" rather
>then "zero" (so it has to be placed in ".data" rather then ".bss" in
>terms of typical implementations if "null pointer" is not represented
>as all bits 0)?

You could place it in a section which is initialized to null pointers,
not all-bits-zero.

>Worse, should `memset(&p, 0, sizeof(void*))' set p to
>the "null pointer" rather then "zero"?

No.
memset(&p, 0, sizeof(void*));
p; /* smegmentation fault allowed here */

>Should casts from int to void*
>convert (int)0 (bits: 0x0) to (void*)0 (bits: 0xffffffff)?

Casts from non-constant ints need not do such a conversion.

>I know that this topic has been discussed a lot. That's even one of the
>reasons I'm not sure what the real answers are - I remember too many of
>them and can't tell the right ones from the wrong ones...

Gordon L. Burditt

Keith Thompson

unread,
Jan 28, 2006, 3:23:30 PM1/28/06
to
gordon...@burditt.org (Gordon Burditt) writes:
> yossi....@gmail.com writes:
[...]

>>- AFAIK I can't `#define NULL 0x10000' since `void* p=0;' should work
>>just like `void* p=NULL'. Is this correct?
>
> You, as programmer, are not allowed to do this.
> You, as compiler implementor, are allowed to do this.

The NULL macro must expand to a null pointer constant. 0x10000 is not
a null pointer constant as the term is defined by the standard, so
it's not immediately obvious that

#define NULL 0x10000

is legal for an implementation, even if converting that value to a
pointer always yields a null pointer value.

On the other hand, C99 6.6p10 says:

An implementation may accept other forms of constant expressions.

It's not clear whether that means an implementation may accept other
forms of null pointer constant (0x10000 is already a constant
expression). And C99 4p6 says:

A conforming implementation may have extensions (including
additional library functions), provided they do not alter the
behavior of any strictly conforming program.

so treating 0x10000 as a null pointer constant is (I think) allowed on
that basis, as long as the implementation documents it.

On the other other hand, since 0 *must* be a null pointer constant,
there's little point in defining NULL as anything other than 0 or
((void*)0). Giving null pointers a representation other than
all-bits-zero doesn't require any extensions to make everything work
properly. And accepting 0x10000 as a null pointer constant would
encourage programmers to write non-portable code that depends on this
assumption.

Even if all-bits-zero is a valid address, you might still consider
representing null pointers as all-bits-zero. Whatever is at that
location, no portable program can access it anyway. If it's something
important, there's some risk of buggy programs clobbering it by
writing through a null pointer -- but then there's going to be some
risk of buggy programs clobbering it by writing through address zero.

BTW, Gordon, please don't snip attribution lines.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

Jack Klein

unread,
Jan 28, 2006, 5:27:54 PM1/28/06
to
On Sat, 28 Jan 2006 13:48:49 +0000 (UTC), "Vladimir S. Oka"
<nov...@btopenworld.com> wrote in comp.lang.c:

> yossi....@gmail.com wrote:
> > - AFAIK I can't `#define NULL 0x10000' since `void* p=0;' should work
> > just like `void* p=NULL'. Is this correct?
>
> Yes and no. Yes, if you're compiler writer, and on your implementation
> NULL pointer representation is 0x10000, so you defined it thus in the
> standard header files. No, if you're trying to re-define NULL in your
> own C program. The part of your sentence after `since` is irrelevant in
> this context (but true).

No, even if you are a compiler writer, you cannot define the macro
NULL as something like (void *)0x10000. Not if you want your compiler
to conform to the C language standard.

The macro NULL is required by the standard to be an
implementation-defined null pointer constant, and the meaning of "null
pointer constant" is precisely defined by the standard:

"An integer constant expression with the value 0, or such an
expression cast to type void *, is called a null pointer constant."

The expression (void *)0x10000 is neither of the two allowed forms.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

Jordan Abel

unread,
Jan 28, 2006, 8:01:42 PM1/28/06
to
On 2006-01-28, Jack Klein <jack...@spamcop.net> wrote:
> On Sat, 28 Jan 2006 13:48:49 +0000 (UTC), "Vladimir S. Oka"
> <nov...@btopenworld.com> wrote in comp.lang.c:
>
>> yossi....@gmail.com wrote:
>> > - AFAIK I can't `#define NULL 0x10000' since `void* p=0;' should work
>> > just like `void* p=NULL'. Is this correct?
>>
>> Yes and no. Yes, if you're compiler writer, and on your implementation
>> NULL pointer representation is 0x10000, so you defined it thus in the
>> standard header files. No, if you're trying to re-define NULL in your
>> own C program. The part of your sentence after `since` is irrelevant in
>> this context (but true).
>
> No, even if you are a compiler writer, you cannot define the macro
> NULL as something like (void *)0x10000. Not if you want your compiler
> to conform to the C language standard.
>
> The macro NULL is required by the standard to be an
> implementation-defined null pointer constant, and the meaning of "null
> pointer constant" is precisely defined by the standard:
>
> "An integer constant expression with the value 0, or such an
> expression cast to type void *, is called a null pointer constant."
>
> The expression (void *)0x10000 is neither of the two allowed forms.

I think you have a funny definition of "implementation-defined".

Joe Wright

unread,
Jan 28, 2006, 8:12:04 PM1/28/06
to

I am not a guru. The only pointer value defined by the C standard is
NULL. It is defined variously as 0 or (void*)0. The zero value is chosen
specifically because it is within the range of all possible pointer
values. No pointer value other than NULL can be tested for validity.

A C program can safely assume NULL as zero. If it is really not it is
the implementation's job to take care of it and lie to us.

The conditional (NULL == 0) will yield 1 everywhere. Or not?

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---

Peter Nilsson

unread,
Jan 28, 2006, 8:13:40 PM1/28/06
to
Jordan Abel wrote:
> On 2006-01-28, Jack Klein <jack...@spamcop.net> wrote:
> > ... even if you are a compiler writer, you cannot define the macro

> > NULL as something like (void *)0x10000. Not if you want your compiler
> > to conform to the C language standard.
> >
> > The macro NULL is required by the standard to be an
> > implementation-defined null pointer constant, and the meaning of "null
> > pointer constant" is precisely defined by the standard:
> >
> > "An integer constant expression with the value 0, or such an
> > expression cast to type void *, is called a null pointer constant."
> >
> > The expression (void *)0x10000 is neither of the two allowed forms.
>
> I think you have a funny definition of "implementation-defined".

You mean the funny one in the standard...

implementation-defined behavior
unspecified behavior where each implementation documents how the
choice is made

unspecified behavior
behavior where this International Standard provides two or more
possibilities and imposes no further requirements on which is
chosen in any instance

This allows an implementation to do...

#define NULL __null

...where __null is an integer constant expression with the value 0, but
it doesn't allow...

#define NULL ((void *)0x10000)

...since 0x10000 is clearly not an integer constant expression with the
value 0.

Of course, such an implementation could carefully check for stringising
of the NULL macro, under the 'as if' rule, thereby preventing a
strictly conforming program from confirming that it is not an
ordinary null pointer constant, but why would an implementaion
bother?

--
Peter

Keith Thompson

unread,
Jan 28, 2006, 8:50:15 PM1/28/06
to

There was a lengthy discussion of this not too long ago; I think it
was in comp.std.c.

In my opinion, the phrase "implementation-defined null pointer
constant" in C99 7.17p3 (which defines the NULL macro) does *not* give
permission to extend the standard's definition of "null pointer
constant" in 6.3.2.3p3; it merely allows an implementation to chose
something that's a null pointer constant and requires it to document
its choice.

On the other hand, 4p6 says:

A conforming implementation may have extensions (including
additional library functions), provided they do not alter the
behavior of any strictly conforming program.

which does mean that an implementation may define additional null
pointer constants (such as (void*)0x10000), as long as it documents
them and as long as no strictly conforming programs are affected.

But since 0 is already a perfectly portable null pointer constant,
there's not much point in doing so. (It might be useful to define a
special form of null pointer constant for error checking, so a
diagnostic is produced when NULL is used in a non-pointer context, but
it's possible to do that anyway.)

Keith Thompson

unread,
Jan 28, 2006, 9:35:39 PM1/28/06
to
Joe Wright <joeww...@comcast.net> writes:
[...]

> I am not a guru. The only pointer value defined by the C standard is
> NULL.

I'm not sure what you mean by that. NULL is a macro that expands to a
null pointer constant; a null pointer constant yields a null pointer
value when converted to a pointer type. So NULL is two steps removed
from an actual pointer value. (A null pointer constant is a syntactic
entity that occurs only in source code; a null pointer value occurs
only during the execution of a program.)

Yes, I'm being picky; it's not entirely unreasonable to use NULL as a
shorthand for a null pointer value. But the address of any object or
function is a pointer value.

> It is defined variously as 0 or (void*)0.

Basically yes. I'm going to go into pedantic mode; feel free to
ignore the next few paragraphs.

(void*)0 is not a valid definition for NULL because of C99 7.1.2p5:

Any definition of an object-like macro described in this clause
shall expand to code that is fully protected by parentheses where
necessary, so that it groups in an arbitrary expression as if it
were a single identifier.

If you have
#define NULL (void*)0
then the expression
sizeof NULL
becomes a syntax error.

On the other hand, it's not clear that ((void*)0) is a valid
definition for NULL either. NULL is required to be a null pointer
constant. The standard's definition of a null pointer constant is:

An integer constant expression with the value 0, or such an
expression cast to type void *

6.5.1p5 says that:

A parenthesized expression is a primary expression. Its type and
value are identical to those of the unparenthesized expression. It
is an lvalue, a function designator, or a void nexpression if the
unparenthesized expression is, respectively, an lvalue, a function
designator, or a void expression.

We cannot directly conclude from this that a parenthesized null
pointer constant is a null pointer constant.

However, just as a matter of common sense, it seems obvious that
((void*)0) *should* be a null pointer constant, and therefore a valid
definition of NULL. Some implementations do define NULL this way.
The wording of the standard should be corrected.

End of pedantry (for now).

> The zero value is
> chosen specifically because it is within the range of all possible
> pointer values.

I'm not sure what this means. Pointers are not numbers; they don't
have ranges.

> No pointer value other than NULL can be tested for
> validity.

Again, the address of any object or function is a pointer value. What
do you mean by "can be tested for validity"?

> A C program can safely assume NULL as zero. If it is really not it is
> the implementation's job to take care of it and lie to us.

A null pointer value is a particular value of a pointer type, just as
0 is a particular value of an integer type and 0.0 is a particular
value of a floating-point type. It just happens that the language
uses a very strange way to represent a null pointer literal.

It's best to think of a null pointer value as a null pointer value,
not as "zero". The fact that 0 can be used *in source* to represent a
run-time null pointer value is just an oddity that's hidden behind the
NULL macro.

> The conditional (NULL == 0) will yield 1 everywhere. Or not?

Yes, because both will be converted to a common type. If NULL is 0,
it's just (0 == 0), which is an integer comparison. If NULL is
((void*)0), it's a pointer comparison.

Jordan Abel

unread,
Jan 28, 2006, 9:36:40 PM1/28/06
to

#define NULL ((void *)0xFFFFFFFF), assuming that that is in fact a null
pointer, will guarantee that.

Chris Torek

unread,
Jan 29, 2006, 3:30:24 AM1/29/06
to
In article <1138455155.3...@g49g2000cwa.googlegroups.com>

<yossi....@gmail.com> wrote:
>Hi!
>
>There is a system where 0x0 is a valid address, but 0xffffffff isn't.
>How can null pointers be treated by a compiler (besides the typical
>"solution" of still using 0x0 for "null")?

Ignoring all the debate that has been triggered by your list
(which I have snipped), here is the answer I think you may be
looking for.

Suppose you are the compiler-writer for this machine. Suppose
further that you have decide to use 0xffffffff (all-one-bits)
as your internal representation for the null pointer, so that:

char *p = 0;
use(*p);

will trap at runtime, even though 0 is a valid address. How will
you, as the compiler-writer, achieve this?

The answer lies in your code generator. At any point in dealing
with the conversion of C source code to machine-level instructions,
you *always* know the type(s) of all the operand(s) of every
operator. This is of course absolutely necessary on most machines.
Consider, for instance, something like:

sum = a + b;

If a and b are ordinary "int"s, you probably need to generate an
integer-add instruction with integer operands:

ld r1, ... # load variable "a" into integer register
ld r2, ... # load variable "b" into integer register
add r0,r1,r2 # compute integer sum, reg+reg -> reg
st r0, ... # store sum back to memory

while if "a" and "b" are ordinary "double"s, you probably need to
generate a double-add instruction with double operands:

ldd f2, ... # load double "a" into f2/f3 register pair
ldd f4, ... # load double "b" into f4/f5 register pair
addd f0,f2,f4 # compute double-precision sum
std f0, ... # store sum back into memory

If one operand is an "int" and one is a "double", you have to
convert the int to a double and do the addition as two doubles,
and so on. The only way to know which instructions to generate is
to keep track of the types of all the operands.

So, now you have a chunk of C source level code that includes
the line:

p = 0;

where "p" has type "char *", i.e., a pointer type. The operand on
the right-hand-side of the assignment is an integer *and* is a
constant (you must keep track of this, too, but of course you will,
in order to do constant-folding). So you have an assignment that
has "integer constant zero" as the value to be assigned. Inside
the compiler, you check, and you GENERATE DIFFERENT CODE!

if (is_integer_constant(rhs) && value(rhs) == 0)
generate_store(lhs, 0xffffffff);
else
...

and thus, what comes out in the machine code is:

mov r0, -1 # set r0 to 0xffffffff
st r0, ... # store to pointer "p"

Likewise, in places where you have a comparision or test that
might be comparing a pointer to integer-constant-zero, you check
for this in the compiler, and generate the appropriate code:

is_null = false;
if (is_pointer(lhs) && is_integer_constant(rhs) && value(rhs) == 0) {
is_null = true;
ptr_operand = lhs;
} else if (is_pointer(rhs) &&
is_integer_constant(lhs) && value(lhs) == 0) {
is_null = true;
ptr_operand = rhs;
}
if (is_null)
generate_compare(ptr_operand, 0xffffffff);
else
...

There is only one place this goes wrong, and that is:

extern void somefunc(int firstparam, ...);
...
somefunc(3, ptr1, 0, ptr3); /* where "0" is meant to be a null pointer */

Here, inside your compiler, you see that the second parameter is
an integer constant zero, so you check the function prototype to
see if you need a pointer in this position. All you have is the
literal "..." part, so you must assume that this is really an
integer here, not a pointer. You pass zero (0x00000000) instead
of 0xffffffff. But this source code call is wrong! The programmer
*should* have used a cast:

somefunc(3, ptr1, (char *)0, ptr3);

In this version, you have a cast of an integer constant zero to a
pointer type, which produces 0xffffffff as appropriate, and only
then looks at the prototype. As before, there is no extra information
given by the prototype, but now you pass 0xffffffff as desired.

Now, given that I believe you have indeed correctly identified how
to do this inside the compiler:

>- AFAIK I can identify contexts where `0' is used as a pointer and use
>the numeric value 0xffffffff rather then 0x0. Is this correct?

Yes.

>In particular, should `void* p;' initialize p to "null pointer" rather
>then "zero" (so it has to be placed in ".data" rather then ".bss" in
>terms of typical implementations if "null pointer" is not represented
>as all bits 0)?

If "p" has static duration, yes. If "p" has automatic duration it
does not have to have any useful value upon creation. Note that
this also applies to structures containing pointers:

struct S { int a; long *b; double c; void *d; };
static struct S x;

will have to put x in a data segment in order to set x.b and x.d
to 0xffffffff internally. Unions may also contain pointers, but
in C89 only the first element is initialized, so only if the first
element is a pointer will you have to do this. (C99 offers designated
initializers, but those just fall out naturally.)

(You may, depending on implementation, want to have an "all one
bits" segment that you place either before or after your "bss"
segment. This will handle pointers that are not members of
structures.)

>Worse, should `memset(&p, 0, sizeof(void*))' set p to the
>"null pointer" rather then "zero"?

No.

>Should casts from int to void* convert (int)0 (bits: 0x0) to (void*)0
>(bits: 0xffffffff)?

If the (int)0 is an integer *constant*, yes (because semantically,
a cast is just an assignment to an unnamed temporary, except that
an actual temporary would be an lvalue and a cast produces an rvalue).

If the int that happens to contain zero is *not* a constant, this
is up to you -- but I would not. This allows programmers to write:

int zero = 0;
char *p = (char *)zero;
... now use *p to access hardware location 0 ...

>I know that this topic has been discussed a lot. That's even one of the
>reasons I'm not sure what the real answers are - I remember too many of
>them and can't tell the right ones from the wrong ones...

The usual answer is to skip all of this and simply make sure that
hardware-location-zero is occupied, so that no *C* object or function
actually has address zero. Of course, this does not trap erroneous
null-pointer dereferences, but C implementations are rarely kind
to programmers that way. We seem to prefer to drive our race cars
without seatbelts. :-)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.

Alex Fraser

unread,
Jan 29, 2006, 6:03:09 AM1/29/06
to
"Keith Thompson" <ks...@mib.org> wrote in message
news:lnlkwzv...@nuthaus.mib.org...

> On the other hand, it's not clear that ((void*)0) is a valid
> definition for NULL either. NULL is required to be a null pointer
> constant. The standard's definition of a null pointer constant is:
>
> An integer constant expression with the value 0, or such an
> expression cast to type void *
>
> 6.5.1p5 says that:
>
> A parenthesized expression is a primary expression. Its type and
> value are identical to those of the unparenthesized expression. It
> is an lvalue, a function designator, or a void nexpression if the
> unparenthesized expression is, respectively, an lvalue, a function
> designator, or a void expression.
>
> We cannot directly conclude from this that a parenthesized null
> pointer constant is a null pointer constant.

(In N869,) 6.6 says that a constant expression is (grammatically) a
conditional expression - with some constraints, of course.

Grammatically, a primary expression is a conditional expression.

Alex


Christian Bau

unread,
Jan 29, 2006, 7:16:52 AM1/29/06
to
In article <1138455155.3...@g49g2000cwa.googlegroups.com>,
yossi....@gmail.com wrote:

All your compiler has to do is to make sure that a cast from an integer
zero to a pointer type produces a null pointer, and a cast from a null
pointer to an integer type produces an integer zero.

If for example sizeof (int) == sizeof (void *), and a null pointer of
type (void *) has exactly the same representation as an int with a value
of 0x10000, then the cast from int to void* might translate to an "add"
instruction which adds 0x10000, and a cast from void* to int might
translate to a "subtract" instruction which subtracts 0x10000, or both
might translate to an "exclusive or" instruction which does an
exclusive-or with a value of 0x10000.

One other bit where the compiler must be careful: All static and extern
pointer variables without an explicit initialisation must be initialised
to a null pointer. Some compilers just produce code that sets everything
to zeroes and then fills in bits that are explicitely initialised; that
will not be enough if null pointers or floating point zeroes are not all
bits zeroes.

Joe Wright

unread,
Jan 29, 2006, 12:07:20 PM1/29/06
to
Pointer values share some characteristics of numbers. You can add to
them, subtract from them and subtract one from another. Pointers have a
range from 0 to the maximum allowed memory address.

As the C programmer doesn't know the memory model of the target, the
natural choice for a 'pointer to nothing' would be 0 or (void*)0.

>
>> No pointer value other than NULL can be tested for
>>validity.
>
>
> Again, the address of any object or function is a pointer value. What
> do you mean by "can be tested for validity"?
>

Consider..
int *ptr;
ptr = malloc(100 * sizeof *ptr);
if (ptr == NULL) {/* do something about the failure */}
.. use ptr with careless abandon ..
free(ptr);
.. use ptr at your peril ..
The value of ptr probably hasn't changed but the call to free(ptr) has
made it indeterminate. You can't examine ptr to determine its validity.

>
>>A C program can safely assume NULL as zero. If it is really not it is
>>the implementation's job to take care of it and lie to us.
>
>
> A null pointer value is a particular value of a pointer type, just as
> 0 is a particular value of an integer type and 0.0 is a particular
> value of a floating-point type. It just happens that the language
> uses a very strange way to represent a null pointer literal.
>
> It's best to think of a null pointer value as a null pointer value,
> not as "zero". The fact that 0 can be used *in source* to represent a
> run-time null pointer value is just an oddity that's hidden behind the
> NULL macro.
>
>
>>The conditional (NULL == 0) will yield 1 everywhere. Or not?
>
>
> Yes, because both will be converted to a common type. If NULL is 0,
> it's just (0 == 0), which is an integer comparison. If NULL is
> ((void*)0), it's a pointer comparison.
>

--

Christian Bau

unread,
Jan 29, 2006, 1:15:30 PM1/29/06
to
In article <lnk6ckw...@nuthaus.mib.org>,
Keith Thompson <ks...@mib.org> wrote:

> gordon...@burditt.org (Gordon Burditt) writes:
> > yossi....@gmail.com writes:
> [...]
> >>- AFAIK I can't `#define NULL 0x10000' since `void* p=0;' should work
> >>just like `void* p=NULL'. Is this correct?
> >
> > You, as programmer, are not allowed to do this.
> > You, as compiler implementor, are allowed to do this.
>
> The NULL macro must expand to a null pointer constant. 0x10000 is not
> a null pointer constant as the term is defined by the standard, so
> it's not immediately obvious that
>
> #define NULL 0x10000
>
> is legal for an implementation, even if converting that value to a
> pointer always yields a null pointer value.
>
> On the other hand, C99 6.6p10 says:
>
> An implementation may accept other forms of constant expressions.

I think the C Standard defines "constant expressions" a bit before null
pointer constants. A null pointer constant is then defined as a
"constant expression" which has some additional properties, for example
either being an integer expression of value 0, or such an expression
cast to void*. 0x10000 cannot be a null pointer constant, because it
doesn't have a value of zero.

I think an implementation might for example define strlen ("") as a
constant which would have a value of zero and might therefore become a
null pointer constant (but I think there will other restrictions in the
definition of "integer constant expression" and "null pointer constant"
that prevent it from being a null pointer constant).

Christian Bau

unread,
Jan 29, 2006, 1:22:20 PM1/29/06
to
In article <3-OdnQWZtt_-i0He...@comcast.com>,
Joe Wright <joeww...@comcast.net> wrote:


> A C program can safely assume NULL as zero. If it is really not it is
> the implementation's job to take care of it and lie to us.

No. Saying "NULL is zero" is nonsense. NULL can either be an integer
constant with a value of 0, or it is such a constant cast to void*. In
that case is a pointer. Saying that a pointer is zero is pure nonsense.
A pointer can point to an object, or it can point past the last byte of
an object, or it can be a null pointer which points to no object at all,
or it can be some indeterminate value, but it cannot be zero. It cannot
be pi, or e, or sqrt (2), or one, or zero, or any other number. It
cannot be green, yellow, red or blue either. These are all things that
don't make any sense for pointers.

In a comparison (p == 0), where p is a pointer, the integer constant 0
is converted to a null pointer because there is a special rule in the C
language that in this kind of situation, integer constants of value 0
are automatically converted to pointers, while any other integer
constants, for example those with a value of 1, are not converted. The
pointer p is _never_ compared with a zero. It is always compared with
another pointer value.

Christian Bau

unread,
Jan 29, 2006, 1:25:19 PM1/29/06
to
In article <slrndtoamr.3...@random.yi.org>,
Jordan Abel <rand...@gmail.com> wrote:

> #define NULL ((void *)0xFFFFFFFF), assuming that that is in fact a null
> pointer, will guarantee that.

But it is not a null pointer constant, because 0xFFFFFFFF doesn't have a
value of zero.

Vladimir S. Oka

unread,
Jan 29, 2006, 1:27:59 PM1/29/06
to
Joe Wright wrote:

> Keith Thompson wrote:
>> Joe Wright <joeww...@comcast.net> writes:

<snipped quite a lot, hopefully not too much>

>> I'm not sure what this means. Pointers are not numbers; they don't
>> have ranges.
>>
> Pointer values share some characteristics of numbers. You can add to
> them, subtract from them and subtract one from another. Pointers have
> a range from 0 to the maximum allowed memory address.

I think associating pointers with numbers, despite the `similarities`
quoted above is not a good idea. The `addition` and `subtraction` work
in (not so) subtly different ways than expected of `ordinary` numbers
(think pointers to a structure with size of 17 bytes). Also, ranges are
not necessarily contiguous in the sense the ranges of real world
numbers are (an architecture may have no memory mapped in the byte
address range 0x1000 to 0x2000, as it's reserved for memory-mapped
I/O).

>
> As the C programmer doesn't know the memory model of the target, the
> natural choice for a 'pointer to nothing' would be 0 or (void*)0.

This may be the `natural` assumption, but it suffers the same problems
as outlined above.

IMHO, It might have been better if C went the Pascal way and had just
NULL, and didn't allow numbers to be mixed with pointers, unless as a
non-standard extension.

My tuppence, anyway...

Cheers

Vladimir


--
Heavy, adj.:
Seduced by the chocolate side of the force.

Christian Bau

unread,
Jan 29, 2006, 1:31:19 PM1/29/06
to
In article <2LWdnWjRqcp...@eclipse.net.uk>,
"Alex Fraser" <m...@privacy.net> wrote:

The pedantic argument is that ((void *) 0) is not an integer constant
with value 0, cast to void*, but an integer constant with value 0, cast
to void*, and put into parentheses. I am quite sure it was not the
intention of the C Standard that this should make a difference. If it
would make a difference, then any programmer writing

char* p = (NULL):

would write non-portable code!

Gordon Burditt

unread,
Jan 29, 2006, 2:46:12 PM1/29/06
to
>> #define NULL ((void *)0xFFFFFFFF), assuming that that is in fact a null
>> pointer, will guarantee that.
>
>But it is not a null pointer constant, because 0xFFFFFFFF doesn't have a
>value of zero.

Is that really true if
((void *)0xffffffff) == 0
which an implementation can ensure?

Gordon L. Burditt

Keith Thompson

unread,
Jan 29, 2006, 2:49:23 PM1/29/06
to
Christian Bau <christ...@cbau.freeserve.co.uk> writes:
[snip]

> All your compiler has to do is to make sure that a cast from an integer
> zero to a pointer type produces a null pointer, and a cast from a null
> pointer to an integer type produces an integer zero.

Not quite. It only has to make sure that a conversion (explicit or
implicit, not just a cast) of an integer *constant* 0 to a pointer
type produces a null pointer. There is no requirement that conversion
of a non-constant zero has to yield a null pointer, or that conversion
of a null pointer value has to yield an integer zero.

For example:

char *null_ptr = 0; /* guaranteed to be a null pointer value */
int zero = 0;
char *maybe_null = (char*)zero; /* may or may not be a null pointer */

The requirements for null pointer constants apply only to compile-time
constructs.

On the other hand, it would almost certainly be easier for the
compiler to make compile-time and run-time integer-to-pointer
conversions consistent. It would be easy to introduce a bug where
value propagation makes the compiler treat the value of zero in the
example above as a constant and treat it as if it were a null pointer
constant. (If null pointers are all-bits-zero, this isn't a problem.)

Keith Thompson

unread,
Jan 29, 2006, 3:19:33 PM1/29/06
to
Joe Wright <joeww...@comcast.net> writes:
> Keith Thompson wrote:
>> Joe Wright <joeww...@comcast.net> writes:
[...]
>>> The zero value is
>>>chosen specifically because it is within the range of all possible
>>>pointer values.
>> I'm not sure what this means. Pointers are not numbers; they don't
>> have ranges.
>>
> Pointer values share some characteristics of numbers. You can add to
> them, subtract from them and subtract one from another. Pointers have
> a range from 0 to the maximum allowed memory address.

Yes, they share *some* of the characteristics of numbers, but not all
of them. For example, pointer arithmetic is defined only with a
single object. There is nothing in the standard that supports the
idea that pointers range from 0 to the "maximum allowed memory
address".

> As the C programmer doesn't know the memory model of the target, the
> natural choice for a 'pointer to nothing' would be 0 or (void*)0.

There's nothing natural about it *unless* you assume a particular
linear memory model. C's definition of null pointer constants is a
relic of the early systems on which it was implemented, which happened
to have such a model (as do many, probably most, systems today).

Think of a pointer as a nearly opaque entity that can designate an
object or function.

A function pointer could be implemented as an index into a table of
functions, having nothing to do with a machine address.

Any valid object pointer value is one of the following:
A null pointer;
A pointer to an object plus an offset (possibly zero) within that
object; or
Something implementation-specific.
(The second is a special case of the third, with a zero offset.) An
implementation could represent each object pointer as a structure
consisting of an object descriptor (perhaps a table index, perhaps
something else) and an offset. Pointer arithmetic would act only on
the offset. No portable code can tell the difference between this and
the more common implementation as a machine address.

And a null pointer is just a special representation (or
representations) indicating that the pointer doesn't point to
anything. There's no fundamental reason why all-bits-zero is a good
choice for this. It's like a floating-point NaN (Not-a-Number);
there's no reason for portable code to care how it's represented.

In fact, I think that demonstrates a flaw in the C model. It's
assumed that there's a "zero" value for each scalar type, and that
these zero values are somehow analagous to each other. But in fact,
there is no integer value corresponding to a null pointer. 0 is just
another ordinary value within the range of valid values; likewise for
a floating-point 0.0. The best analogy is between a nul pointer value
and a floating-point "quiet NaN".

A language slightly better designed than C would have a keyword,
perhaps "nil", to denote a null pointer value; it would be the *only*
valid null pointer constant. Instead, we have some special-case rules
about integer constant expressions with the value 0. These rules are
probably necessary for backward compatibility. Fortunately we can
hide the ugly details behind the NULL macro.

If a program needs to get closer to the metal and use the underlying
machine address representation, an implementation can provide rules
for converting integers to pointers -- but those rules are entirely
implementation-defined (except for the null pointer constant anomaly)
and might not even make sense on a machine with non-linear addressing.

>>> No pointer value other than NULL can be tested for
>>>validity.
>> Again, the address of any object or function is a pointer value.
>> What
>> do you mean by "can be tested for validity"?
>>
> Consider..
> int *ptr;
> ptr = malloc(100 * sizeof *ptr);
> if (ptr == NULL) {/* do something about the failure */}
> .. use ptr with careless abandon ..
> free(ptr);
> .. use ptr at your peril ..
> The value of ptr probably hasn't changed but the call to free(ptr) has
> made it indeterminate. You can't examine ptr to determine its validity.

Right, but that doesn't support your earlier statement. *Any* pointer
value other than an indetermine one can be tested for validity; you
did so on the second line of your example (if malloc() succeeded).

Keith Thompson

unread,
Jan 29, 2006, 3:25:21 PM1/29/06
to
Christian Bau <christ...@cbau.freeserve.co.uk> writes:
> In article <lnk6ckw...@nuthaus.mib.org>,
> Keith Thompson <ks...@mib.org> wrote:
>> gordon...@burditt.org (Gordon Burditt) writes:
>> > yossi....@gmail.com writes:
>> [...]
>> >>- AFAIK I can't `#define NULL 0x10000' since `void* p=0;' should work
>> >>just like `void* p=NULL'. Is this correct?
>> >
>> > You, as programmer, are not allowed to do this.
>> > You, as compiler implementor, are allowed to do this.
>>
>> The NULL macro must expand to a null pointer constant. 0x10000 is not
>> a null pointer constant as the term is defined by the standard, so
>> it's not immediately obvious that
>>
>> #define NULL 0x10000
>>
>> is legal for an implementation, even if converting that value to a
>> pointer always yields a null pointer value.
>>
>> On the other hand, C99 6.6p10 says:
>>
>> An implementation may accept other forms of constant expressions.
>
> I think the C Standard defines "constant expressions" a bit before null
> pointer constants. A null pointer constant is then defined as a
> "constant expression" which has some additional properties, for example
> either being an integer expression of value 0, or such an expression
> cast to void*. 0x10000 cannot be a null pointer constant, because it
> doesn't have a value of zero.
[...]

Ok, I agree that 6.6p10 doesn't give permission to define other forms
of null pointer constants. But 4p6 allows any extension that doesn't
affect any strictly conforming program -- which seems to make 6.6p10
redundant.

Keith Thompson

unread,
Jan 29, 2006, 3:29:46 PM1/29/06
to
Christian Bau <christ...@cbau.freeserve.co.uk> writes:
> In article <3-OdnQWZtt_-i0He...@comcast.com>,
> Joe Wright <joeww...@comcast.net> wrote:
>> A C program can safely assume NULL as zero. If it is really not it is
>> the implementation's job to take care of it and lie to us.
>
> No. Saying "NULL is zero" is nonsense. NULL can either be an integer
> constant with a value of 0, or it is such a constant cast to void*. In
> that case is a pointer. Saying that a pointer is zero is pure nonsense.
> A pointer can point to an object, or it can point past the last byte of
> an object, or it can be a null pointer which points to no object at all,
> or it can be some indeterminate value, but it cannot be zero. It cannot
> be pi, or e, or sqrt (2), or one, or zero, or any other number. It
> cannot be green, yellow, red or blue either. These are all things that
> don't make any sense for pointers.
[...]

Agreed. The use of 0 as a null pointer constant is, IMHO, a
particularly ugly form of overloading. Some people complain about
C++'s use of "<<" and ">>" for I/O; after all, those are shift
operators, and they should act on integers. Likewise, C effectively
overloads 0 as a null pointer constant, even though 0 is naturally an
*integer* constant.

Anyone who thinks this isn't genuinely confusing should explain why
this requires an entire section of the comp.lang.c FAQ.

Keith Thompson

unread,
Jan 29, 2006, 3:52:51 PM1/29/06
to

Gordon, *please* don't snip attribution lines. In following a
discussion, it's important to know who said what. Your headers
indicate that you're using the "trn" newsreader; I'm reasonably sure
it does attributions correctly.

Yes, that's really true. 0xFFFFFFFF doesn't have a value of zero, so
neither 0xFFFFFFFF nor (void*)0xFFFFFFFF is a null pointer constant
within the standard's definition of the term -- even if converting
0xffffffff to void* happens to yield a null pointer value.

A null pointer constant is a specific source construct, not just any
constant expression that happens to evaluate to a null pointer value.

Having said that, an implementation can probably make it a null
pointer constant *as a documented extension* -- but there's little
point in doing so. There are far too many valid null pointer
constants already; we don't need any more.

Alex Fraser

unread,
Jan 29, 2006, 3:57:31 PM1/29/06
to
"Christian Bau" <christ...@cbau.freeserve.co.uk> wrote in message
news:christian.bau-594...@slb-newsm1.svr.pol.co.uk...
[snip]

> The pedantic argument is that ((void *) 0) is not an integer constant
> with value 0, cast to void*, but an integer constant with value 0, cast
> to void*, and put into parentheses.

ITYM "integer constant expression" not "integer constant", but I see your
(and Keith Thompson's) point.

> I am quite sure it was not the intention of the C Standard that this
> should make a difference.

No doubt.

Alex


Joe Wright

unread,
Jan 29, 2006, 4:18:19 PM1/29/06
to

1. What are you drinking?
2. Can I have some?

The pedancy award has to go to Keith Thompson, not you or me.

NULL is a text replacement macro, not any kind of pointer. A pointer is
an object which can hold the address of another object.

Common usage be damned, a value of pointer type is not a pointer. Our
friend malloc() returns a value of (void*) type, not a pointer.

char *p;
p = malloc(100);

The object p is the pointer here, not the value returned by malloc(). It
is argued that functions can return pointers. They can't.

You say a special rule in C requires an integer constant of value 0 to
be converted to a pointer. But a pointer is an object. I presume you
mean a value of pointer type. And you say further that the rule applies
to constants of 0 but not 1. C&V please.

My preference in libation is Jim Beam, an excellent Bourbon.

Keith Thompson

unread,
Jan 29, 2006, 5:38:38 PM1/29/06
to

Um, I almost hesitate to point this out, but I think, you mean
"pedantry". But thanks for the award anyway.

> NULL is a text replacement macro, not any kind of pointer. A pointer
> is an object which can hold the address of another object.
>
> Common usage be damned, a value of pointer type is not a pointer. Our
> friend malloc() returns a value of (void*) type, not a pointer.
>
> char *p;
> p = malloc(100);
>
> The object p is the pointer here, not the value returned by
> malloc(). It is argued that functions can return pointers. They can't.

So your point is that "pointer" should refer only to pointer objects,
and the value of a pointer object should be referred to as an
"address". As I've mentioned before, I actually agree with that, but
the standard doesn't. C99 7.20.3.3, for example, says:

The malloc function returns either a null pointer or a pointer to
the allocated space.

And note that the standard uses the defined term "null pointer", not
"null address", to refer to a particular value. A null pointer is
clearly a value, not an object, and we don't have another common term
for it. You or I might have used different terminology, but if we're
going to communicate meaningfully we need to at least acknowledge the
existence of the terminology used by the standard.

I usually try to use the phrases "pointer value" and "null pointer
value" to avoid any possible confusion, but if I happen to forget I'm
sure you can figure out what I mean from context -- and from common
usage.

Consider that the value of an integer object is commonly called an
integer; why shouldn't the value of a pointer object be called a
pointer?

And it hardly seems fair to accuse someone who uses the standard
terminology of being drunk.

> You say a special rule in C requires an integer constant of value 0 to
> be converted to a pointer. But a pointer is an object. I presume you
> mean a value of pointer type. And you say further that the rule
> applies to constants of 0 but not 1. C&V please.

Yes, of course it means a value of pointer type; that's how the
standard uses the term "pointer".

The C&V is C99 6.3.2.3p3:

An integer constant expression with the value 0, or such an

expression cast to type void *, is called a _null pointer
constant_.55) 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.

Footnote 55 says:

The macro NULL is defined in <stddef.h> (and other headers) as a
null pointer constant; see 7.17.

You've read sections 4 and 5 of the comp.lang.c FAQ, right?

Joe Wright

unread,
Jan 29, 2006, 5:58:07 PM1/29/06
to

What? "Any pointer value other than an indeterminate one can be tested
for validity." How would you determine whether the value of ptr, not
NULL, in the above example was indeterminate? You can't.

Some say even accessing ptr, if its value is indeterminate, invokes
Undefined Behaviour. Does it?

Jack Klein

unread,
Jan 29, 2006, 6:28:54 PM1/29/06
to
On 29 Jan 2006 01:01:42 GMT, Jordan Abel <rand...@gmail.com> wrote
in comp.lang.c:

<sigh>

I agree, that is what you think. And I think the same of yours.
However, the ISO C Standard agrees with my definition.

Let's go step-by-step:

"3.4.4
1 unspecified behavior


behavior where this International Standard provides two or more
possibilities and imposes no further requirements on which is chosen
in any instance"

"3.4.1
1 implementation-defined behavior


unspecified behavior where each implementation documents how the
choice is made"

So implementation-defined behavior is "unspecified behavior" (this
International Standard provides two or more possibilities), namely, in
the case of the NULL macro:

1. "An integer constant expression with the value 0"

2. "such an expression (integer constant expression with the value 0)


cast to type void *"

Now:

"The macros are
NULL
which expands to an implementation-defined null pointer constant; ..."

If NULL was required to expand to an "unspecified" null pointer
constant, the implementation would need to chose between the "two or
more possibilities" provided by the Standard, and need not tell you
which it chose or why.

The only difference due to the fact that NULL must expand to an
"implementation-defined", instead of "unspecified", null pointer
constant is that the implementation is required to document its
choice.

"implementation-defined", in this and in many other cases, is not a
license for an implementation to do anything at all. It must select
one of the specified alternatives.

An implementation might well choose to provide other macros that it
evaluates to a null pointer constant, but to be conforming the macro
NULL must have one of the two forms specified.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

Keith Thompson

unread,
Jan 29, 2006, 7:11:16 PM1/29/06
to
Joe Wright <joeww...@comcast.net> writes:
> Keith Thompson wrote:
>> Joe Wright <joeww...@comcast.net> writes:
>>>Keith Thompson wrote:
>>>>Joe Wright <joeww...@comcast.net> writes:
[...]
>>>>> No pointer value other than NULL can be tested for
>>>>>validity.
>>>>
>>>>Again, the address of any object or function is a pointer value.
>>>>What
>>>>do you mean by "can be tested for validity"?
>>>>
>>>
>>>Consider..
>>> int *ptr;
>>> ptr = malloc(100 * sizeof *ptr);
>>> if (ptr == NULL) {/* do something about the failure */}
>>> .. use ptr with careless abandon ..
>>> free(ptr);
>>> .. use ptr at your peril ..
>>>The value of ptr probably hasn't changed but the call to free(ptr) has
>>>made it indeterminate. You can't examine ptr to determine its validity.
>> Right, but that doesn't support your earlier statement. *Any*
>> pointer
>> value other than an indetermine one can be tested for validity; you
>> did so on the second line of your example (if malloc() succeeded).
>
> What? "Any pointer value other than an indeterminate one can be tested
> for validity." How would you determine whether the value of ptr, not
> NULL, in the above example was indeterminate? You can't.

Please snip irrelevant text when you post a followup.

No, you can't (portably) determine whether it's indeterminate unless
you already know whether it's indeterminate.

> Some say even accessing ptr, if its value is indeterminate, invokes
> Undefined Behaviour. Does it?

Yes, accessing the value of ptr invokes undefined behavior if its
value is indeterminate.

You said that

No pointer value other than NULL can be tested for validity.

The real problem, I think, is that I honestly have no idea what you
mean by that.

Perhaps if you can show an example of "testing a pointer value for
validity", I can understand why a null pointer value is special in
that context.

Assuming that either a null pointer value or a pointer value that
points to an object is considered "valid", *no* pointer value can
meaningfully be tested for validity. If you *know* that it's valid
(either null or non-null), there's no point in testing it. If you
don't know (it might be indeterminate), you can't test it without
risking undefined behavior.

CBFalconer

unread,
Jan 29, 2006, 7:07:46 PM1/29/06
to
Joe Wright wrote:
>
... snip ...

>
> Pointer values share some characteristics of numbers. You can add
> to them,

Within sharp limits.

> subtract from them

Within even sharper limits.

> and subtract one from another.

and this operation is very heavily restricted to pointers to
locations within the same object. Otherwise meaningless.

> Pointers have a range from 0 to the maximum allowed memory address.

Not so. A pointer only has to point. It can do this in any way it
likes, including specifying the phase of the moon when dereferenced
or the need for sacrificial virgins.

As a real life example, consider a magnetic core memory.
Addressing is in terms of x, y, and plane coordinates. This is not
a number. It is a tuple. In modern systems it may be made up of
process id, segment id, page id, page offset, and bit or byte.

--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943


Joe Wright

unread,
Jan 30, 2006, 4:56:13 PM1/30/06
to
Keith Thompson wrote:
> Joe Wright <joeww...@comcast.net> writes:
>
>>Keith Thompson wrote:
>>
>>>Joe Wright <joeww...@comcast.net> writes:
>>>
>>>>Keith Thompson wrote:
>>>>
>>>>>Joe Wright <joeww...@comcast.net> writes:
>
[[ big snip ]]

>>Some say even accessing ptr, if its value is indeterminate, invokes
>>Undefined Behaviour. Does it?
>
>
> Yes, accessing the value of ptr invokes undefined behavior if its
> value is indeterminate.
>
> You said that
>
> No pointer value other than NULL can be tested for validity.
>
> The real problem, I think, is that I honestly have no idea what you
> mean by that.
>
> Perhaps if you can show an example of "testing a pointer value for
> validity", I can understand why a null pointer value is special in
> that context.
>
> Assuming that either a null pointer value or a pointer value that
> points to an object is considered "valid", *no* pointer value can
> meaningfully be tested for validity. If you *know* that it's valid
> (either null or non-null), there's no point in testing it. If you
> don't know (it might be indeterminate), you can't test it without
> risking undefined behavior.
>

You clearly (from the above paragraph) do know what I mean. I'm sorry if
I was confusing. But further if I might,

char *p = malloc(100);
if (p == NULL)

The test is valid because malloc will return NULL or a valid pointer (OK
I said pointer, not address). But if then..

free(p);
...
if (p == NULL)

This test is invalid because p is now indeterminate. Right?

Joe Wright

unread,
Jan 30, 2006, 5:19:54 PM1/30/06
to
You're right, pedantry. No thanks necessary. You deserve it.
I'm going to concede that point, at least until it really annoys me
again. I am of the firm opinion that using 'pointer' ambiguously all
these years in K&R and the Standards has done more to confuse the
subject that anything else. I've been posting about this for ten years
and get little and meek support. OK, I'll be quiet about it for now.

> And it hardly seems fair to accuse someone who uses the standard
> terminology of being drunk.
>

That was meant as a joke. If Christian is reading, if I have offended I
am terribly sorry. I don't have an insulting bone in my body.


>
>>You say a special rule in C requires an integer constant of value 0 to
>>be converted to a pointer. But a pointer is an object. I presume you
>>mean a value of pointer type. And you say further that the rule
>>applies to constants of 0 but not 1. C&V please.
>
>
> Yes, of course it means a value of pointer type; that's how the
> standard uses the term "pointer".
>
> The C&V is C99 6.3.2.3p3:
>
> An integer constant expression with the value 0, or such an
> expression cast to type void *, is called a _null pointer
> constant_.55) 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.
>
> Footnote 55 says:
>
> The macro NULL is defined in <stddef.h> (and other headers) as a
> null pointer constant; see 7.17.
>
> You've read sections 4 and 5 of the comp.lang.c FAQ, right?
>

Sure, lots of times. Even as Chief Pedant, talking down doesn't win points.

Keith Thompson

unread,
Jan 30, 2006, 5:45:11 PM1/30/06
to

I don't mean to be picky, but I really, truly, honestly, do not


understand what you meant. You wrote:

No pointer value other than NULL can be tested for validity.

And to support that statement, you show code in which you perform a
test on a pointer value other than NULL (or rather, one that will be
non-NULL if malloc() succeeds). I really have no idea what you mean
by "tested for validity"; *no* pointer value can be tested for
validity in portable code, for reasons I mentioned above and with
which you seem to agree.

If you can show code in which you test a pointer value of NULL for
validity (whatever that means), and can explain why the same test
could not be performed on a non-NULL pointer, perhaps I can understand
what your statement meant.

(Of course I'm using "NULL" as a verbal shorthand for a null pointer
value.)

Yes, I'm picking on a single statement you made several articles
upthread, but you keep insisting that it's meaningful. Either it
isn't, or I'm missing something important (the latter has certainly
happened before). Perhaps it was just inartfully phrased; if so, I'll
be glad to drop this.

Keith Thompson

unread,
Jan 30, 2006, 5:46:25 PM1/30/06
to
Joe Wright <joeww...@comcast.net> writes:
> Keith Thompson wrote:
[...]

>> You've read sections 4 and 5 of the comp.lang.c FAQ, right?
>>
> Sure, lots of times. Even as Chief Pedant, talking down doesn't win points.

No offense intended. Come to think of it, I don't think I've read
those entire sections myself since they were updated; I probably
should.

Joe Wright

unread,
Jan 30, 2006, 6:09:51 PM1/30/06
to
CBFalconer wrote:
> Joe Wright wrote:
>
> ... snip ...
>
>>Pointer values share some characteristics of numbers. You can add
>>to them,
>
>
> Within sharp limits.
>
>
>> subtract from them
>
>
> Within even sharper limits.
>
>
>> and subtract one from another.
>
>
> and this operation is very heavily restricted to pointers to
> locations within the same object. Otherwise meaningless.
>
>
>>Pointers have a range from 0 to the maximum allowed memory address.
>
>
> Not so. A pointer only has to point. It can do this in any way it
> likes, including specifying the phase of the moon when dereferenced
> or the need for sacrificial virgins.
>
> As a real life example, consider a magnetic core memory.
> Addressing is in terms of x, y, and plane coordinates. This is not
> a number. It is a tuple. In modern systems it may be made up of
> process id, segment id, page id, page offset, and bit or byte.
>
That core memory module you describe is indeed interesting. If I had one
and wanted to address it in a C program with a pointer, how would I go
about it? What object type would the pointer have?

Would I need a special compiler that knows about the module? How would
the innocent C programmer deal with plane coordinates and segment id's
of this subsystem? Or you're just teasing me?

Joe Wright

unread,
Jan 30, 2006, 6:20:38 PM1/30/06
to
Consider it dropped. You and I agree here, we just can't seem to say so.

Gordon Burditt

unread,
Jan 30, 2006, 6:32:22 PM1/30/06
to
>> As a real life example, consider a magnetic core memory.
>> Addressing is in terms of x, y, and plane coordinates. This is not
>> a number. It is a tuple. In modern systems it may be made up of
>> process id, segment id, page id, page offset, and bit or byte.

This could be an interesting setup. Assuming you can have more
than one bank of this memory, it could be made into a number
represented as bit fields consisting of (ABA routing number, plane,
y, x). An integer might consist of 7 bytes, and relative to the
pointer to the integer, you have the bytes at addresses (plane, y,
x):

(0,0,0) (+1,0,0) (-1,0,0) (0,-1,0) (0,+1,0) (0,0,+1) (0,0,-1)
On the other hand, an *unsigned* integer might have bytes at addresses:
(0,0,0) (+1,0,0) (+2,0,0) (+3,0,0) (0,-1,0) (0,-2,0) (0,-3,0)

Now, trying to allocate stuff in memory becomes sort of a 3-dimensional
Tetris puzzle. Any use of the concept "contiguous" gets pretty
much thrown out the window. And trying to use allocated stuff with
malloc() becomes darn near impossible if malloc() allocates a 1-D
memory vector.

>That core memory module you describe is indeed interesting. If I had one
>and wanted to address it in a C program with a pointer, how would I go
>about it? What object type would the pointer have?

Just about any pointer can be represented as a bunch of bits, optionally
divided into bit fields to represent various stuff (segment number,
ring number, offset, protection level, global/local, etc.)

>Would I need a special compiler that knows about the module? How would
>the innocent C programmer deal with plane coordinates and segment id's
>of this subsystem? Or you're just teasing me?

The implementation I described makes functions like malloc() pretty
much hopeless (and therefore trying to put C on it is teasing you).
The C++ new operator knows the type, so it could allocate wierd
shapes of memory needed to handle funky objects.

Gordon L. Burditt

Christian Bau

unread,
Jan 30, 2006, 6:38:18 PM1/30/06
to
In article <11tq6s4...@corp.supernews.com>,
gordon...@burditt.org (Gordon Burditt) wrote:

0xffffffff still doesn't have a value of zero.

Take a more concrete example: On many existing applications, you will
find that


((void *) 0xffffffff00000000) == 0

0xffffffff00000000 is a constant of type unsigned long long, with the
lowest 32 bits equal to zero. On many implementations with 32 bit
pointers, this constant cast to a pointer type will produce a null
pointer. But 0xffffffff00000000 is not a null pointer constant.

Christian Bau

unread,
Jan 30, 2006, 6:39:22 PM1/30/06
to
In article <lnpsmau...@nuthaus.mib.org>,
Keith Thompson <ks...@mib.org> wrote:

> Christian Bau <christ...@cbau.freeserve.co.uk> writes:
> [snip]
> > All your compiler has to do is to make sure that a cast from an integer
> > zero to a pointer type produces a null pointer, and a cast from a null
> > pointer to an integer type produces an integer zero.
>
> Not quite. It only has to make sure that a conversion (explicit or
> implicit, not just a cast) of an integer *constant* 0 to a pointer
> type produces a null pointer. There is no requirement that conversion
> of a non-constant zero has to yield a null pointer, or that conversion
> of a null pointer value has to yield an integer zero.
>
> For example:
>
> char *null_ptr = 0; /* guaranteed to be a null pointer value */
> int zero = 0;
> char *maybe_null = (char*)zero; /* may or may not be a null pointer */
>
> The requirements for null pointer constants apply only to compile-time
> constructs.

I believe this has been added as a requirement in C99.

Christian Bau

unread,
Jan 30, 2006, 6:43:09 PM1/30/06
to
In article <x6OdndznMvGErEDe...@comcast.com>,
Joe Wright <joeww...@comcast.net> wrote:

> Christian Bau wrote:
> > In article <3-OdnQWZtt_-i0He...@comcast.com>,
> > Joe Wright <joeww...@comcast.net> wrote:
> >
> >
> >
> >>A C program can safely assume NULL as zero. If it is really not it is
> >>the implementation's job to take care of it and lie to us.
> >
> >
> > No. Saying "NULL is zero" is nonsense. NULL can either be an integer
> > constant with a value of 0, or it is such a constant cast to void*. In
> > that case is a pointer. Saying that a pointer is zero is pure nonsense.
> > A pointer can point to an object, or it can point past the last byte of
> > an object, or it can be a null pointer which points to no object at all,
> > or it can be some indeterminate value, but it cannot be zero. It cannot
> > be pi, or e, or sqrt (2), or one, or zero, or any other number. It
> > cannot be green, yellow, red or blue either. These are all things that
> > don't make any sense for pointers.
> >
> > In a comparison (p == 0), where p is a pointer, the integer constant 0
> > is converted to a null pointer because there is a special rule in the C
> > language that in this kind of situation, integer constants of value 0
> > are automatically converted to pointers, while any other integer
> > constants, for example those with a value of 1, are not converted. The
> > pointer p is _never_ compared with a zero. It is always compared with
> > another pointer value.
>
> 1. What are you drinking?
> 2. Can I have some?

Seems you had some already. Seems you had plenty too much already. Take
a copy of the C Standard, read it carefully, then read my post again.

Christian Bau

unread,
Jan 30, 2006, 6:49:59 PM1/30/06
to
In article <43DD58D2...@yahoo.com>,
CBFalconer <cbfal...@yahoo.com> wrote:

> Joe Wright wrote:
> >
> ... snip ...
> >
> > Pointer values share some characteristics of numbers. You can add
> > to them,
>
> Within sharp limits.
>
> > subtract from them
>
> Within even sharper limits.
>
> > and subtract one from another.
>
> and this operation is very heavily restricted to pointers to
> locations within the same object. Otherwise meaningless.
>
> > Pointers have a range from 0 to the maximum allowed memory address.
>
> Not so. A pointer only has to point. It can do this in any way it
> likes, including specifying the phase of the moon when dereferenced
> or the need for sacrificial virgins.
>
> As a real life example, consider a magnetic core memory.
> Addressing is in terms of x, y, and plane coordinates. This is not
> a number. It is a tuple. In modern systems it may be made up of
> process id, segment id, page id, page offset, and bit or byte.

Just take an old x86 implementation with segments and offsets. The null
pointer is represented by a null segment with offset 0. All other
pointers are represented by valid segments (and segments other than the
null segment are most definitely not all valid! ) and an offset.

This doesn't correspond to memory addresses at all; memory addresses can
actually change due to demand paging, where the complete memory
addressed by one segment can be swapped to the harddisk and can be
swapped in later at a different memory location.

Adding any number to a null pointer on such an implementation will
never, ever result in a valid pointer.

Joe Wright

unread,
Jan 30, 2006, 6:50:15 PM1/30/06
to
Keith Thompson wrote:
> Joe Wright <joeww...@comcast.net> writes:
>
>>Keith Thompson wrote:
>
> [...]
>
>>>You've read sections 4 and 5 of the comp.lang.c FAQ, right?
>>>
>>
>>Sure, lots of times. Even as Chief Pedant, talking down doesn't win points.
>
>
> No offense intended. Come to think of it, I don't think I've read
> those entire sections myself since they were updated; I probably
> should.
>
No offence taken. Peace. I really enjoy C. I began in 1988 if I recall
correctly with a CP/M compiler from Software Toolworks and a tattered
copy of K&R1. I still have that copy of the Old Testament. I got
interested again in the 90's and followed X3J11 as closely as I could.
The C89 result was good. Especially prototypes and therefore implicit
conversions. I think I have a reasonable handle on how C works.

Dennis Ritchie are Brian Kernighan are heroes of mine. I am not
particularly enticed by or enamoured of C99. Neither here nor there.

Christian Bau

unread,
Jan 30, 2006, 6:52:06 PM1/30/06
to
In article <Nr-dnf8L5oTnFkPe...@comcast.com>,
Joe Wright <joeww...@comcast.net> wrote:

> You clearly (from the above paragraph) do know what I mean. I'm sorry if
> I was confusing. But further if I might,
>
> char *p = malloc(100);
> if (p == NULL)
>
> The test is valid because malloc will return NULL or a valid pointer (OK
> I said pointer, not address). But if then..

malloc will not return NULL. It may return a null pointer. A null
pointer is not the same as NULL. NULL is a null pointer constant, but it
can be an int, or a long, or an unsigned long etc.


> free(p);
> ...
> if (p == NULL)
>
> This test is invalid because p is now indeterminate. Right?

Completely irrelevant to this discussion.

Keith Thompson

unread,
Jan 30, 2006, 7:03:17 PM1/30/06
to
Christian Bau <christ...@cbau.freeserve.co.uk> writes:
> In article <lnpsmau...@nuthaus.mib.org>,
> Keith Thompson <ks...@mib.org> wrote:
[...]

>> For example:
>>
>> char *null_ptr = 0; /* guaranteed to be a null pointer value */
>> int zero = 0;
>> char *maybe_null = (char*)zero; /* may or may not be a null pointer */
>>
>> The requirements for null pointer constants apply only to compile-time
>> constructs.
>
> I believe this has been added as a requirement in C99.

What has? Do you mean that maybe_null in the example is required to
be a null pointer under C99?

I don't believe that's correct. In particular, I don't believe the
requirements have changed significantly between C90 and C99. (Of
course I've been wrong before.) Can you provide chapter and verse?

Keith Thompson

unread,
Jan 30, 2006, 7:17:23 PM1/30/06
to
Christian Bau <christ...@cbau.freeserve.co.uk> writes:
> In article <Nr-dnf8L5oTnFkPe...@comcast.com>,
> Joe Wright <joeww...@comcast.net> wrote:
>
>> You clearly (from the above paragraph) do know what I mean. I'm sorry if
>> I was confusing. But further if I might,
>>
>> char *p = malloc(100);
>> if (p == NULL)
>>
>> The test is valid because malloc will return NULL or a valid pointer (OK
>> I said pointer, not address). But if then..
>
> malloc will not return NULL. It may return a null pointer. A null
> pointer is not the same as NULL. NULL is a null pointer constant, but it
> can be an int, or a long, or an unsigned long etc.

As long as we're being picky, NULL isn't a null pointer constant; it's
a macro that expands to a null pointer constant. If I were going to
be even pickier, I might say that NULL is a sequence of four
characters that, taken together in an appropriate context in a C
source file, form a preprocessing token that happens to be a macro
name that is expanded to a null pointer constant.

Similarly, given
int x = 42;
I might say that x has the value 42, even though 42 is an integer
constant (or a sequence of two characters), not an integer value.
(The trouble there is that we don't have a good name for the value
other than 42.)

The whole point of using a symbol (a word, an identifier, a mark on a
clay tablet, a meaningful grunt) is that the symbol is a shorthand for
the thing it represents. In this case, NULL is fairly clearly meant
to be a shorthand for the thing that it represents, namely a null
pointer value.

Having said all that, I agree that NULL is not a very *good*
conversational shorthand for "null pointer value", partly because it
makes more sense as a shorthand for a null pointer constant than for a
null pointer value (a very important distinction) and partly because
we have an unambiguous term for a null pointer value, namely "null
pointer value". But I think a brief clarification of that point would
be sufficient when, as in this case, the intent is reasonably clear.

Keith Thompson

unread,
Jan 30, 2006, 7:20:12 PM1/30/06
to
Keith Thompson <ks...@mib.org> writes:
> Christian Bau <christ...@cbau.freeserve.co.uk> writes:
>> In article <Nr-dnf8L5oTnFkPe...@comcast.com>,
>> Joe Wright <joeww...@comcast.net> wrote:
>>
>>> You clearly (from the above paragraph) do know what I mean. I'm sorry if
>>> I was confusing. But further if I might,
>>>
>>> char *p = malloc(100);
>>> if (p == NULL)
>>>
>>> The test is valid because malloc will return NULL or a valid pointer (OK
>>> I said pointer, not address). But if then..
>>
>> malloc will not return NULL. It may return a null pointer. A null
>> pointer is not the same as NULL. NULL is a null pointer constant, but it
>> can be an int, or a long, or an unsigned long etc.
>
> As long as we're being picky, NULL isn't a null pointer constant; it's
> a macro that expands to a null pointer constant. If I were going to
> be even pickier, I might say that NULL is a sequence of four
> characters that, taken together in an appropriate context in a C
> source file, form a preprocessing token that happens to be a macro
> name that is expanded to a null pointer constant.
[snip]

Yeah, that was pedantic, even for me. 8-)}

Joe Wright

unread,
Jan 30, 2006, 8:00:26 PM1/30/06
to

I sincerely apologize for the drinking crack. I thought it would be
funny. It was not. Again, I apologize.

I was probably reacting to your condescending attitude. No biggie.

Rod Pemberton

unread,
Jan 30, 2006, 9:49:21 PM1/30/06
to

"Keith Thompson" <ks...@mib.org> wrote in message
news:ln64o1d...@nuthaus.mib.org...

> Christian Bau <christ...@cbau.freeserve.co.uk> writes:
> > In article <Nr-dnf8L5oTnFkPe...@comcast.com>,
> > Joe Wright <joeww...@comcast.net> wrote:
> >
> >> You clearly (from the above paragraph) do know what I mean. I'm sorry
if
> >> I was confusing. But further if I might,
> >>
> >> char *p = malloc(100);
> >> if (p == NULL)
> >>
> >> The test is valid because malloc will return NULL or a valid pointer
(OK
> >> I said pointer, not address). But if then..
> >
> > malloc will not return NULL. It may return a null pointer. A null
> > pointer is not the same as NULL. NULL is a null pointer constant, but it
> > can be an int, or a long, or an unsigned long etc.
>
> As long as we're being picky, NULL isn't a null pointer constant; it's
> a macro that expands to a null pointer constant. If I were going to
> be even pickier, I might say that NULL is a sequence of four
> characters that, taken together in an appropriate context in a C
> source file, form a preprocessing token that happens to be a macro
> name that is expanded to a null pointer constant.

Actually, if you want to be _really_ picky, it, apparently, doesn't have to
expand to _anything_ as long as the compiler has an internal representation
for it. If you pull the code from GCC 4.0.2 and GLIBC 2.3.6 (current
versions), you'll see the compiler creates a special node for NULL in the
code generator. As far as I can tell, it appears that node is given special
attributes, and no value is ever inserted into the node. (But, I could be
wrong. It is quite complex... )

#define NULL (__null)

__null triggers the special code.


Rod Pemberton


Jordan Abel

unread,
Jan 30, 2006, 11:13:22 PM1/30/06
to

You have to be able to stringize it, it's a macro.

CBFalconer

unread,
Jan 30, 2006, 10:08:10 PM1/30/06
to
Joe Wright wrote:
> CBFalconer wrote:
>
... snip ...

>>
>> Not so. A pointer only has to point. It can do this in any way it
>> likes, including specifying the phase of the moon when dereferenced
>> or the need for sacrificial virgins.
>>
>> As a real life example, consider a magnetic core memory.
>> Addressing is in terms of x, y, and plane coordinates. This is not
>> a number. It is a tuple. In modern systems it may be made up of
>> process id, segment id, page id, page offset, and bit or byte.
>
> That core memory module you describe is indeed interesting. If I had
> one and wanted to address it in a C program with a pointer, how
> would I go about it? What object type would the pointer have?
>
> Would I need a special compiler that knows about the module? How
> would the innocent C programmer deal with plane coordinates and
> segment id's of this subsystem? Or you're just teasing me?

The C programmer, innocent or guilty, need not know anything about
the mundane details of the pointer guts. The system designer, on
the other hand, has to worry about it all. That is why a cast
between integral values and pointers may occur, but the result may
be meaningless.

Christian Bau

unread,
Jan 31, 2006, 4:53:23 AM1/31/06
to
In article <lnacdde...@nuthaus.mib.org>,
Keith Thompson <ks...@mib.org> wrote:

> Christian Bau <christ...@cbau.freeserve.co.uk> writes:
> > In article <lnpsmau...@nuthaus.mib.org>,
> > Keith Thompson <ks...@mib.org> wrote:
> [...]
> >> For example:
> >>
> >> char *null_ptr = 0; /* guaranteed to be a null pointer value */
> >> int zero = 0;
> >> char *maybe_null = (char*)zero; /* may or may not be a null pointer */
> >>
> >> The requirements for null pointer constants apply only to compile-time
> >> constructs.
> >
> > I believe this has been added as a requirement in C99.
>
> What has? Do you mean that maybe_null in the example is required to
> be a null pointer under C99?
>
> I don't believe that's correct. In particular, I don't believe the
> requirements have changed significantly between C90 and C99. (Of
> course I've been wrong before.) Can you provide chapter and verse?

From the n1124 draft:

6.3.2.3 Pointers:

3. An integer constant expression with the value 0, or such an
expression cast to type void *, is called a null pointer constant. 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 anyobject or function.

5. An integer may be converted to any pointer type. Except as previously
specified, the result is implementation-defined, might not be correctly
aligned, might not point to an entity of the referenced type, and might
be a trap representation.

6.3.2.3.3 only talks about conversions, it doesn't talk about when
conversions happen (which has a special case for null pointer
constants). It says what the result of a conversion from an integer type
to a pointer type is in one special case. Note that we have here a full
conversion, and not a substitution.

I assume that the result of a conversion can only depend on the value
and the type of the thing that is converted, which implies that anything
that has a type and a value that could be the type and value of a null
pointer constant _must_ be converted to a null pointer. (I don't think
it is possible to have a null pointer constant of type char or short, so
converting a char or short of value 0 to pointer type might not be
guaranteed to produce a null pointer with this reasoning).

As an example, in

char* p = (char *) 0;

the special rules for null pointer constants are not invoked;

char* p = (char *) 1;

would be just as legal; it is just a conversion from int to char*. The C
Standard defines the result in the very strict case we have here, that a
null pointer constant is converted, but the result of a conversion
cannot depend on this fact. Zeroes that are not null pointer constants
are not mentioned in the rule, but they cannot be converted differently.

The result is implementation defined; an implementation would not be
free to define different results for

(char *) 1
(char *) (1 + 0)
(char *) (int) (1.73f)

because they all convert the same value. Neither can it define different
results for different zeroes.

Keith Thompson

unread,
Jan 31, 2006, 5:46:30 AM1/31/06
to

To summarize your argument:

(1) The standard guarantees that an integer constant expression with
the value 0, when converted to a pointer type, yields a null
pointer value.

(2) The result of a conversion depends only on the value and type of
the operand.

(3) Therefore, the integer value 0, when converted to a pointer type,
yields a null pointer value.

I'm not convinced that (2) is necessarily required. (It's going to be
true in the majority of real-world implementations, on which null
pointers are represented as all-bits-zero, but those aren't the cases
we're worried about.)

The conversion of an integer constant expression is a special case.
If it had been intended for the conversion of a non-constant zero to
yield a null pointer, the standard could have said so, and it would
have been simpler than the current wording.

In particular, I believe the following could be a conforming
implementation:

Pointers are 32 bits. A null pointer is represented uniquely as
0xffffffff. A pointer with the representation 0x00000000 is not a
null pointer. Conversion of an integer constant expression with the
value zero to a pointer type yields a null pointer value (as required
by the standard). Conversion of a non-constant integer expression to
a pointer type yields a pointer value with the same representation as
the integer (possibly zero-extended or truncated).

For example:

void *null_ptr = 0; /* obviously a null pointer */
void *null_ptr2 = (void*)0xffffffff; /* a null pointer */
int zero = 0;
void *zero_ptr = (void*)zero; /* not a null pointer */

null_ptr2's value is a null pointer, but (void*)0xffffffff is not a
null pointer constant.

I admit that having (void*)0 and (void*)zero yield different values is
counterintuitive, but so is the whole idea of C's null pointer
constants IMHO. C's definition of a null pointer constant is so
narrow that I think it has to allow for this possibility.

Gordon Burditt

unread,
Jan 31, 2006, 1:39:15 PM1/31/06
to
>>>> #define NULL ((void *)0xFFFFFFFF), assuming that that is in fact a null
>>>> pointer, will guarantee that.
>>>
>>>But it is not a null pointer constant, because 0xFFFFFFFF doesn't have a
>>>value of zero.
>>
>> Is that really true if
>> ((void *)0xffffffff) == 0
>> which an implementation can ensure?
>
>Gordon, *please* don't snip attribution lines. In following a
>discussion, it's important to know who said what.

It is more important not to misattribute someone's words to someone else.

>Your headers
>indicate that you're using the "trn" newsreader; I'm reasonably sure
>it does attributions correctly.

If I don't snip attributions, I get complaints of the form "I didn't
say that" from at least two people complaining that I attributed
the SAME text to each of them. On *EVERY* *SINGLE* *POST*. Even
if there was only one attribution left in. And some of them threaten
lawsuits. If attributions are supposed to indicate who said what,
it's not working, as clearly not everyone interprets them the same
way.

attribution -> misattribution

Note that it's completely irrelevant as to whether *I* can interpret
attributions correctly. I think I can, but I doubt anyone else
cares. And I think what was said is much more important than who
said it, at least most of the time.


>Yes, that's really true. 0xFFFFFFFF doesn't have a value of zero, so
>neither 0xFFFFFFFF nor (void*)0xFFFFFFFF is a null pointer constant
>within the standard's definition of the term -- even if converting
>0xffffffff to void* happens to yield a null pointer value.
>
>A null pointer constant is a specific source construct, not just any
>constant expression that happens to evaluate to a null pointer value.

Ok, so it's source, not runtime.

>Having said that, an implementation can probably make it a null
>pointer constant *as a documented extension* -- but there's little
>point in doing so. There are far too many valid null pointer
>constants already; we don't need any more.

But at runtime, you'd have to have all null pointer values compare
equal to all other null pointer values, right? So if on a particular
implementation, a segment number of 0 indicates a null pointer,
regardless of the offset, protection ring, or assorted other bits
making up a pointer, the code that compares pointers would have to
deal with this?

Gordon l. Burditt

Walter Roberson

unread,
Jan 31, 2006, 2:40:59 PM1/31/06
to
In article <11tvbmj...@corp.supernews.com>,

Gordon Burditt <gordon...@burditt.org> wrote:
>But at runtime, you'd have to have all null pointer values compare
>equal to all other null pointer values, right? So if on a particular
>implementation, a segment number of 0 indicates a null pointer,
>regardless of the offset, protection ring, or assorted other bits
>making up a pointer, the code that compares pointers would have to
>deal with this?

Yes, for any given object type, two null pointers are guaranteed
to compare equal, even if they do not have the same internal
representation.

This is not -necessarily- as bad as the code that compares pointers
needing to iterate through all the different null pointer representations.
The compiler knows that pointer types at the time of the
comparison, so if some of the null pointer representations are not
possible for a given type, then the compiler would not need to
test that possibility. In particular, if there happens to be
exactly one null pointer representation per type (but that different
types might have different null pointer representations) then only
one test would need to be made.

This comparison process is potentially further simplified by the
fact that one cannot convert pointers directly between
incompatible types without going through void* [if I recall correctly].
The conversion into void* could produce a "canonical" null pointer
and the conversion of the "canonical" null pointer into a different
pointer type would choose one of the null pointer representations
valid for that type; in this way, one only has to deal with the
null pointer representations valid within the type. One thing to
watch out for here is that when a pointer is converted to void* and
converted back to the same type, the original pointer and the
double-converted one must compare equal -- but in the end this just
comes down to potentially needing to be able to compare multiple null
pointer representations for a single type.


If I were implementing a system with multiple null pointers, I
suspect I would, for each pointer comparison, insert type-specific
code for each of the pointers, that detected the various null pointer
possibilities and converted into a canonical null pointer. This would
give you a comparison that was linear in the number of different
null pointer representations, rather than one that was proportional
to the square of the number of representations.
--
I was very young in those days, but I was also rather dim.
-- Christopher Priest

Keith Thompson

unread,
Jan 31, 2006, 4:51:56 PM1/31/06
to
gordon...@burditt.org (Gordon Burditt) writes:
>>>>> #define NULL ((void *)0xFFFFFFFF), assuming that that is in fact a null
>>>>> pointer, will guarantee that.
>>>>
>>>>But it is not a null pointer constant, because 0xFFFFFFFF doesn't have a
>>>>value of zero.
>>>
>>> Is that really true if
>>> ((void *)0xffffffff) == 0
>>> which an implementation can ensure?
>>
>>Gordon, *please* don't snip attribution lines. In following a
>>discussion, it's important to know who said what.
>
> It is more important not to misattribute someone's words to someone else.

Agreed, but ...

>>Your headers
>>indicate that you're using the "trn" newsreader; I'm reasonably sure
>>it does attributions correctly.
>
> If I don't snip attributions, I get complaints of the form "I didn't
> say that" from at least two people complaining that I attributed
> the SAME text to each of them. On *EVERY* *SINGLE* *POST*. Even
> if there was only one attribution left in. And some of them threaten
> lawsuits. If attributions are supposed to indicate who said what,
> it's not working, as clearly not everyone interprets them the same
> way.

I vaguely recall some problems (possibly yours?) in which an
attribution line was left in with no corresonding quoted text, so that
the attribution appeared to be incorrect *unless* the reader carefully
counted the '>' characters.

I've never, or rarely, had that problem. Here's what I do:

1. Snip any quoted text that's irrelevant to the followup.

2. For each attribution, if the attribution line itself is preceded by
exactly N '>' characters, delete it if there's no remaining quoted
text preceded by exactly N+1 '>' characters.

It's not difficult. If you do that, you shouldn't get any complaints.
If you continue to drop attribution lines, you *will* get complaints.

> attribution -> misattribution
>
> Note that it's completely irrelevant as to whether *I* can interpret
> attributions correctly. I think I can, but I doubt anyone else
> cares. And I think what was said is much more important than who
> said it, at least most of the time.

I agree that what was said is more important than who said it -- but
who said it *is* somewhat important.

>>Yes, that's really true. 0xFFFFFFFF doesn't have a value of zero, so
>>neither 0xFFFFFFFF nor (void*)0xFFFFFFFF is a null pointer constant
>>within the standard's definition of the term -- even if converting
>>0xffffffff to void* happens to yield a null pointer value.
>>
>>A null pointer constant is a specific source construct, not just any
>>constant expression that happens to evaluate to a null pointer value.
>
> Ok, so it's source, not runtime.
>
>>Having said that, an implementation can probably make it a null
>>pointer constant *as a documented extension* -- but there's little
>>point in doing so. There are far too many valid null pointer
>>constants already; we don't need any more.
>
> But at runtime, you'd have to have all null pointer values compare
> equal to all other null pointer values, right? So if on a particular
> implementation, a segment number of 0 indicates a null pointer,
> regardless of the offset, protection ring, or assorted other bits
> making up a pointer, the code that compares pointers would have to
> deal with this?

We're talking about two different things. Having multiple null
pointer values (at runtime) calls for some extra work by the compiler,
such as in the code that does pointer comparison, but it shouldn't be
a problem for the programmer. Having multiple forms of *null pointer
constant* (0, 0UL, '\0', (void*)('-'-'-')) is required by the
language, and is a source of confusion; an implementation may be
allowed to define additional forms, but there's little benefit in
doing so, and certainly no benefit for anyone writing portable code.

Actually, that's not quite true. An implementation could have

enum { __null = 0 };
#define NULL __null

to make any use of the NULL macro recognizable after preproecessing;
it could then use this as a way to issue warnings (non-required
diagnoistics) for any use of NULL in a non-pointer context. (That
doesn't even require a language extension.)

But treating 0xffffffff as a null pointer constant just because
0xffffffff happens to be a representation of a null pointer value
would be largely pointless.

Keith Thompson

unread,
Jan 31, 2006, 4:55:47 PM1/31/06
to
robe...@ibd.nrc-cnrc.gc.ca (Walter Roberson) writes:
[snip]
[snip]

No, you recall incorrectly. C99 6.3.2.3p7:

A pointer to an object or incomplete type may be converted to a
pointer to a different object or incomplete type.

(followed by caveats about undefined behavior for incorrect
alignment).

But a compiler could certainly implement pointer-to-pointer conversion
by converting to void* and then to the other type.

Flash Gordon

unread,
Jan 31, 2006, 4:09:06 PM1/31/06
to
Gordon Burditt wrote:
>>>>> #define NULL ((void *)0xFFFFFFFF), assuming that that is in fact a null
>>>>> pointer, will guarantee that.
>>>> But it is not a null pointer constant, because 0xFFFFFFFF doesn't have a
>>>> value of zero.
>>> Is that really true if
>>> ((void *)0xffffffff) == 0
>>> which an implementation can ensure?
>> Gordon, *please* don't snip attribution lines. In following a
>> discussion, it's important to know who said what.
>
> It is more important not to misattribute someone's words to someone else.
>
>> Your headers
>> indicate that you're using the "trn" newsreader; I'm reasonably sure
>> it does attributions correctly.
>
> If I don't snip attributions, I get complaints of the form "I didn't
> say that" from at least two people complaining that I attributed
> the SAME text to each of them. On *EVERY* *SINGLE* *POST*. Even
> if there was only one attribution left in. And some of them threaten
> lawsuits. If attributions are supposed to indicate who said what,
> it's not working, as clearly not everyone interprets them the same
> way.
>
> attribution -> misattribution

It may be the case on some groups you frequent, but seeing as most of
the posts I see here and else where have attributions and don't generate
such complaints this suggests to me that either:
1) When you leave in attributions you do them in a non-standard way
2) You have a lot of dealings on a group where people don't understand
the conventional way attributions work.

> Note that it's completely irrelevant as to whether *I* can interpret
> attributions correctly. I think I can, but I doubt anyone else
> cares. And I think what was said is much more important than who
> said it, at least most of the time.

I also care about who said what and find it annoying when a post does
not have proper attributions. I strongly suspect others here feel the
same way.

>> Yes, that's really true. 0xFFFFFFFF doesn't have a value of zero, so
>> neither 0xFFFFFFFF nor (void*)0xFFFFFFFF is a null pointer constant
>> within the standard's definition of the term -- even if converting
>> 0xffffffff to void* happens to yield a null pointer value.
>>
>> A null pointer constant is a specific source construct, not just any
>> constant expression that happens to evaluate to a null pointer value.
>
> Ok, so it's source, not runtime.

Yes.

>> Having said that, an implementation can probably make it a null
>> pointer constant *as a documented extension* -- but there's little
>> point in doing so. There are far too many valid null pointer
>> constants already; we don't need any more.
>
> But at runtime, you'd have to have all null pointer values compare
> equal to all other null pointer values, right? So if on a particular
> implementation, a segment number of 0 indicates a null pointer,
> regardless of the offset, protection ring, or assorted other bits
> making up a pointer, the code that compares pointers would have to
> deal with this?

Yes, or ensure that valid C code only generates one form of null
pointer. So it is exactly the same as the situation where you can have
both +ve and -ve zeros, either only one type must be generated or they
must compare equal.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.

CBFalconer

unread,
Jan 31, 2006, 4:58:05 PM1/31/06
to
Gordon Burditt wrote:
>
... snip ...

>>
>> Gordon, *please* don't snip attribution lines. In following a
>> discussion, it's important to know who said what.
>
> It is more important not to misattribute someone's words to
> someone else.
>
>> Your headers indicate that you're using the "trn" newsreader;
>> I'm reasonably sure it does attributions correctly.
>
> If I don't snip attributions, I get complaints of the form "I didn't
> say that" from at least two people complaining that I attributed
> the SAME text to each of them. On *EVERY* *SINGLE* *POST*. Even
> if there was only one attribution left in. And some of them threaten
> lawsuits. If attributions are supposed to indicate who said what,
> it's not working, as clearly not everyone interprets them the same
> way.
>
> attribution -> misattribution
>
> Note that it's completely irrelevant as to whether *I* can interpret
> attributions correctly. I think I can, but I doubt anyone else
> cares. And I think what was said is much more important than who
> said it, at least most of the time.

Come on now. All it takes is the ability to count up to 3 or 4
'>'s at the head of each line you quote. Find the max, and remove
attribution lines which have that many or more '>'s. Also yell at
idiots who use non-standard quote markers. I am fairly sure you
are capable of that.

Christian Bau

unread,
Jan 31, 2006, 7:04:49 PM1/31/06
to
In article <lny80w3...@nuthaus.mib.org>,
Keith Thompson <ks...@mib.org> wrote:

Null pointer constants are not very counter-intuitive really. All that
the C Standard says is that in some cases, when you write 0 in a
program, you actually get for example (char *) 0. There are similar
situations: If a is an array, then in many situations where you write a,
you actually get &a[0]. Or if you declare a function parameter as an
array, like in int f (int a[10]); you actually get a pointer like int f
(int* a).

Jordan Abel

unread,
Jan 31, 2006, 7:05:02 PM1/31/06
to
On 2006-01-31, Flash Gordon <sp...@flash-gordon.me.uk> wrote:
>> But at runtime, you'd have to have all null pointer values compare
>> equal to all other null pointer values, right? So if on a particular
>> implementation, a segment number of 0 indicates a null pointer,
>> regardless of the offset, protection ring, or assorted other bits
>> making up a pointer, the code that compares pointers would have to
>> deal with this?
>
> Yes, or ensure that valid C code only generates one form of null
> pointer. So it is exactly the same as the situation where you can have
> both +ve and -ve zeros, either only one type must be generated or they
> must compare equal.

Another example is on some x86 implementations, where pointer comparison
in general is on the offset only, and offset bits of 0 make a null
pointer. Of course, this also provides a reason that casting a null
pointer to an integer type doesn't necessarily result in 0. 3000:0000
cast to long would become 0x30000000L, not 0L

Keith Thompson

unread,
Jan 31, 2006, 7:48:01 PM1/31/06
to

Whether something is counterintuitive or not is bound to be a matter
of opinion. I won't say you're wrong, but I will say that my opinion
is unchanged. If it it were only the integer literal 0 that's
overloaded as a null pointer constant, it wouldn't be so bad, but the
standard requires 0, '\0', 0UL, ('/'/'/'-'/'/'/'), and (3/4) to be
treated as null pointer constants as well (probably so compilers can
perform constant-folding but don't have to remember they've done it),
but *doesn't* require a non-constant integer value of 0 to yield a
null pointer value when converted (at least, I don't *think* it does;
there's still some debate on that point). It leads too many people to
assume that a null pointer *value* is represented as all-bits-zero
(which isn't an entirely unreasonable assumption given that
integer-to-pointer conversion usually just reinterprets the bits), or
at least that pointers are really just integers.

Just look at the time we spend discussing it here, and how much room
it takes up in the FAQ. And think how much of this we could have
avoided if the original C had added a keyword "nil" and made it the
*only* valid null pointer constant.

If you find all that stuff intuitive, you have better (or more C-like)
intuition than I do.

0 new messages