By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,836 Members | 2,059 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,836 IT Pros & Developers. It's quick & easy.

NULL with representation other then all bits 0

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

Jan 28 '06 #1
Share this Question
Share on Google+
64 Replies


P: n/a
yo***********@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

Jan 28 '06 #2

P: n/a
Vladimir S. Oka wrote:
yo***********@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.
Jan 28 '06 #3

P: n/a
>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
Jan 28 '06 #4

P: n/a
go***********@burditt.org (Gordon Burditt) writes:
yo***********@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.
Jan 28 '06 #5

P: n/a
On Sat, 28 Jan 2006 13:48:49 +0000 (UTC), "Vladimir S. Oka"
<no****@btopenworld.com> wrote in comp.lang.c:
yo***********@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/~a...FAQ-acllc.html
Jan 28 '06 #6

P: n/a
On 2006-01-28, Jack Klein <ja*******@spamcop.net> wrote:
On Sat, 28 Jan 2006 13:48:49 +0000 (UTC), "Vladimir S. Oka"
<no****@btopenworld.com> wrote in comp.lang.c:
yo***********@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".
Jan 29 '06 #7

P: n/a
Keith Thompson wrote:
go***********@burditt.org (Gordon Burditt) writes:
yo***********@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.


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 ---
Jan 29 '06 #8

P: n/a
Jordan Abel wrote:
On 2006-01-28, Jack Klein <ja*******@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

Jan 29 '06 #9

P: n/a
Jordan Abel <ra*******@gmail.com> writes:
On 2006-01-28, Jack Klein <ja*******@spamcop.net> wrote:
On Sat, 28 Jan 2006 13:48:49 +0000 (UTC), "Vladimir S. Oka"
<no****@btopenworld.com> wrote in comp.lang.c:
yo***********@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".


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 (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.
Jan 29 '06 #10

P: n/a
Joe Wright <jo********@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.

--
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.
Jan 29 '06 #11

P: n/a
On 2006-01-29, Joe Wright <jo********@comcast.net> wrote:
Keith Thompson wrote:
go***********@burditt.org (Gordon Burditt) writes:
yo***********@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.


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?


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

P: n/a
In article <11**********************@g49g2000cwa.googlegroups .com>
<yo***********@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 (4039.22'N, 11150.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.
Jan 29 '06 #13

P: n/a
"Keith Thompson" <ks***@mib.org> wrote in message
news:ln************@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
Jan 29 '06 #14

P: n/a
In article <11**********************@g49g2000cwa.googlegroups .com>,
yo***********@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")?

- 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...


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.
Jan 29 '06 #15

P: n/a
Keith Thompson wrote:
Joe Wright <jo********@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.

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.


--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jan 29 '06 #16

P: n/a
In article <ln************@nuthaus.mib.org>,
Keith Thompson <ks***@mib.org> wrote:
go***********@burditt.org (Gordon Burditt) writes:
yo***********@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).
Jan 29 '06 #17

P: n/a
In article <3-******************************@comcast.com>,
Joe Wright <jo********@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.
Jan 29 '06 #18

P: n/a
In article <sl***********************@random.yi.org>,
Jordan Abel <ra*******@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.
Jan 29 '06 #19

P: n/a
Joe Wright wrote:
Keith Thompson wrote:
Joe Wright <jo********@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.

Jan 29 '06 #20

P: n/a
In article <2L********************@eclipse.net.uk>,
"Alex Fraser" <me@privacy.net> wrote:
"Keith Thompson" <ks***@mib.org> wrote in message
news:ln************@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.


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!
Jan 29 '06 #21

P: n/a
>> #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
Jan 29 '06 #22

P: n/a
Christian Bau <ch***********@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 (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.
Jan 29 '06 #23

P: n/a
Joe Wright <jo********@comcast.net> writes:
Keith Thompson wrote:
Joe Wright <jo********@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 (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.
Jan 29 '06 #24

P: n/a
Christian Bau <ch***********@cbau.freeserve.co.uk> writes:
In article <ln************@nuthaus.mib.org>,
Keith Thompson <ks***@mib.org> wrote:
go***********@burditt.org (Gordon Burditt) writes:
> yo***********@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 (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.
Jan 29 '06 #25

P: n/a
Christian Bau <ch***********@cbau.freeserve.co.uk> writes:
In article <3-******************************@comcast.com>,
Joe Wright <jo********@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 (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.
Jan 29 '06 #26

P: n/a
go***********@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. 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.

--
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.
Jan 29 '06 #27

P: n/a
"Christian Bau" <ch***********@cbau.freeserve.co.uk> wrote in message
news:ch*********************************@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
Jan 29 '06 #28

P: n/a
Christian Bau wrote:
In article <3-******************************@comcast.com>,
Joe Wright <jo********@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?

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 ---
Jan 29 '06 #29

P: n/a
Joe Wright <jo********@comcast.net> writes:
Christian Bau wrote:
In article <3-******************************@comcast.com>,
Joe Wright <jo********@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?

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) 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.
Jan 29 '06 #30

P: n/a
Keith Thompson wrote:
Joe Wright <jo********@comcast.net> writes:
Keith Thompson wrote:
Joe Wright <jo********@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).


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?

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jan 29 '06 #31

P: n/a
On 29 Jan 2006 01:01:42 GMT, Jordan Abel <ra*******@gmail.com> wrote
in comp.lang.c:
On 2006-01-28, Jack Klein <ja*******@spamcop.net> wrote:
On Sat, 28 Jan 2006 13:48:49 +0000 (UTC), "Vladimir S. Oka"
<no****@btopenworld.com> wrote in comp.lang.c:
yo***********@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".


<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/~a...FAQ-acllc.html
Jan 29 '06 #32

P: n/a
Joe Wright <jo********@comcast.net> writes:
Keith Thompson wrote:
Joe Wright <jo********@comcast.net> writes:
Keith Thompson wrote:
Joe Wright <jo********@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.

--
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.
Jan 30 '06 #33

P: n/a
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
Jan 30 '06 #34

P: n/a
Keith Thompson wrote:
Joe Wright <jo********@comcast.net> writes:
Keith Thompson wrote:
Joe Wright <jo********@comcast.net> writes:

Keith Thompson wrote:

>Joe Wright <jo********@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
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jan 30 '06 #35

P: n/a
Keith Thompson wrote:
Joe Wright <jo********@comcast.net> writes:
Christian Bau wrote:
In article <3-******************************@comcast.com>,
Joe Wright <jo********@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?

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.

You're right, pedantry. No thanks necessary. You deserve it.
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?

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.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jan 30 '06 #36

P: n/a
Joe Wright <jo********@comcast.net> writes:
Keith Thompson wrote:
Joe Wright <jo********@comcast.net> writes:
Keith Thompson wrote:
Joe Wright <jo********@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?


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 (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.
Jan 30 '06 #37

P: n/a
Joe Wright <jo********@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.

--
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.
Jan 30 '06 #38

P: n/a
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
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jan 30 '06 #39

P: n/a
Keith Thompson wrote:
Joe Wright <jo********@comcast.net> writes:
Keith Thompson wrote:
Joe Wright <jo********@comcast.net> writes:

Keith Thompson wrote:

>Joe Wright <jo********@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?

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.

Consider it dropped. You and I agree here, we just can't seem to say so.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jan 30 '06 #40

P: n/a
>> 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
Jan 30 '06 #41

P: n/a
In article <11*************@corp.supernews.com>,
go***********@burditt.org (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?


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.
Jan 30 '06 #42

P: n/a
In article <ln************@nuthaus.mib.org>,
Keith Thompson <ks***@mib.org> wrote:
Christian Bau <ch***********@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.

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.)

Jan 30 '06 #43

P: n/a
In article <x6******************************@comcast.com>,
Joe Wright <jo********@comcast.net> wrote:
Christian Bau wrote:
In article <3-******************************@comcast.com>,
Joe Wright <jo********@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.
Jan 30 '06 #44

P: n/a
In article <43***************@yahoo.com>,
CBFalconer <cb********@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.
Jan 31 '06 #45

P: n/a
Keith Thompson wrote:
Joe Wright <jo********@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.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jan 31 '06 #46

P: n/a
In article <Nr******************************@comcast.com>,
Joe Wright <jo********@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.
Jan 31 '06 #47

P: n/a
Christian Bau <ch***********@cbau.freeserve.co.uk> writes:
In article <ln************@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 (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.
Jan 31 '06 #48

P: n/a
Christian Bau <ch***********@cbau.freeserve.co.uk> writes:
In article <Nr******************************@comcast.com>,
Joe Wright <jo********@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 (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.
Jan 31 '06 #49

P: n/a
Keith Thompson <ks***@mib.org> writes:
Christian Bau <ch***********@cbau.freeserve.co.uk> writes:
In article <Nr******************************@comcast.com>,
Joe Wright <jo********@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-)}

--
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.
Jan 31 '06 #50

64 Replies

This discussion thread is closed

Replies have been disabled for this discussion.