Velocity Reviews > NULL with representation other then all bits 0

NULL with representation other then all bits 0

Christian Bau
Guest
Posts: n/a

 01-29-2006
In article <(E-Mail Removed)>,
"Alex Fraser" <(E-Mail Removed)> wrote:

> "Keith Thompson" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
> > 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.

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
Guest
Posts: n/a

 01-29-2006
>> #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
Guest
Posts: n/a

 01-29-2006
Christian Bau <(E-Mail Removed)> 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 (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <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.

Keith Thompson
Guest
Posts: n/a

 01-29-2006
Joe Wright <(E-Mail Removed)> writes:
> Keith Thompson wrote:
>> Joe Wright <(E-Mail Removed)> 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

> 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 (The_Other_Keith) (E-Mail Removed) <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.

Keith Thompson
Guest
Posts: n/a

 01-29-2006
Christian Bau <(E-Mail Removed)> writes:
> In article <(E-Mail Removed)>,
> Keith Thompson <(E-Mail Removed)> wrote:
>> (E-Mail Removed) (Gordon Burditt) writes:
>> > (E-Mail Removed) 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 (The_Other_Keith) (E-Mail Removed) <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.

Keith Thompson
Guest
Posts: n/a

 01-29-2006
Christian Bau <(E-Mail Removed)> writes:
> In article <(E-Mail Removed)>,
> Joe Wright <(E-Mail Removed)> 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
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 (The_Other_Keith) (E-Mail Removed) <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.

Keith Thompson
Guest
Posts: n/a

 01-29-2006
(E-Mail Removed) (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?

indicate that you're using the "trn" newsreader; I'm reasonably sure

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.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <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.

Alex Fraser
Guest
Posts: n/a

 01-29-2006
"Christian Bau" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
[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
Guest
Posts: n/a

 01-29-2006
Christian Bau wrote:
> In article <(E-Mail Removed)>,
> Joe Wright <(E-Mail Removed)> 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?

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.

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

Keith Thompson
Guest
Posts: n/a

 01-29-2006
Joe Wright <(E-Mail Removed)> writes:
> Christian Bau wrote:
>> In article <(E-Mail Removed)>,
>> Joe Wright <(E-Mail Removed)> 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?
>
> The pedancy award has to go to Keith Thompson, not you or me.

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?

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <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.