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

offsetof() macro

P: n/a
Hi,

Can somebody please help me grok the offsetof() macro?

I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?

Thanks.

Simon

--
"Being a social outcast helps you stay concentrated on the really important
things, like thinking and hacking." - Eric S. Raymond

Nov 15 '05 #1
Share this Question
Share on Google+
44 Replies


P: n/a
Simon Morgan wrote:

Hi,

Can somebody please help me grok the offsetof() macro?

I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?


The offset of s_ptr->item could be taken as

((char *)&s_ptr->item) - ((char *)s_ptr)

Rather than having to create an actual "s_ptr" to use such a macro, it
can be shortcutted by simply using "((s *)constant)". By making the
"constant" zero, it also eliminates the need for the right-half of the
above equation.

There is nothing wrong with a NULL pointer, as long as you don't
dereference it. Taking it's address is fine.
Side question: what happens on platforms where NULL is not all-bits-
zero?

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:Th*************@gmail.com>
Nov 15 '05 #2

P: n/a
Simon Morgan <si***@16hz.net> wrote:
Hi,

Can somebody please help me grok the offsetof() macro?
I'll try.
I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?


Preamble: note that the definition of the offsetof macro is highly
implementation specific. The one I'll use below is only one possible
solution, which happens to work on a variety of systems, while
miserably failing on others. An implementation may even call an
inbuilt function to calculate the offset of struct members by "black
magic" (read: compiler symbol table).

Ok, let's have a look at it:

#define offsetof(s,m) (size_t)&(((s *)0)->m)

with s being the name of a structure type and m the name of a member
within that structure.

Now, if we want to get a grip at a complex C expression, we simply
read it inside out:

0 We take the integer constant 0,

(s *)0 cast to a pointer-to-object-of-type-s, thus pointing
at address 0; we now _pretend_ that at address 0 an
actual object of type s resides.

((s *)0)->m Now look at the member m of that object, which we do
not access, but instead

&(((s *)0)->m) take the address of. Since the address of the
structure object is 0, the address of m happens to
equal its offset in bytes.

(size_t)&(((s *)0)->m) Finally, we cast the result to a suitable
integral data type.

Note, however, that this specific implementation relies upon the fact,
that the underlying architecture allows for _meaningfully_ conversion
of an integral value into a memory address an vice versa.

HTH
Best regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
clc frequent answers: http://benpfaff.org/writings/clc.
Nov 15 '05 #3

P: n/a
Kenneth Brody wrote:
Simon Morgan wrote:

Hi,

Can somebody please help me grok the offsetof() macro?

I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?


The offset of s_ptr->item could be taken as

((char *)&s_ptr->item) - ((char *)s_ptr)

Rather than having to create an actual "s_ptr" to use such a macro, it
can be shortcutted by simply using "((s *)constant)". By making the
"constant" zero, it also eliminates the need for the right-half of the
above equation.

There is nothing wrong with a NULL pointer, as long as you don't
dereference it. Taking it's address is fine.
Side question: what happens on platforms where NULL is not all-bits-
zero?


Both "NULL" and "offsetof" are defined in <stddef.h> (7.17 Common de?nitions
<stddef.h>).

NULL is implementation-defined, but (6.3.2.3 Pointers) an integer constant
with value 0 is the same as NULL.

I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to 0x1234.

If NULL is defined as something other than 0 (incl. non-integer values),
such a construct as:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
would not yield the correct value, hence why it is defined in <stddef.h>
along with NULL.

Note that I'm not an expert on the C standard unlike many people here, and I
could be giving totally wrong information.

BTW, I had to retrieve the "offsetof" of an array element, so here's a
complementary macro, only valid with a NULL value of 0, if what I said
above is correct.

#define array_offsetof(BASETYPE,ARRAY,INDEX) ((size_t) &((BASETYPE(*)ARRAY
0)[0]INDEX)

ex.:
int a[5][10][15];
/* offset of a[1][3] */
int offset = array_offsetof(int, [5][10][15], [1][3]);
--
Eric Laberge
Nov 15 '05 #4

P: n/a
Eric Laberge ha scritto:
Kenneth Brody wrote:

Simon Morgan wrote:
Hi,

Can somebody please help me grok the offsetof() macro?

I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?


The offset of s_ptr->item could be taken as

((char *)&s_ptr->item) - ((char *)s_ptr)

Rather than having to create an actual "s_ptr" to use such a macro, it
can be shortcutted by simply using "((s *)constant)". By making the
"constant" zero, it also eliminates the need for the right-half of the
above equation.

There is nothing wrong with a NULL pointer, as long as you don't
dereference it. Taking it's address is fine.
Side question: what happens on platforms where NULL is not all-bits-
zero?

Both "NULL" and "offsetof" are defined in <stddef.h> (7.17 Common de?nitions
<stddef.h>).

NULL is implementation-defined, but (6.3.2.3 Pointers) an integer constant
with value 0 is the same as NULL.

I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to 0x1234.


Are you sure? I've just compiled (gcc) and executed the code below, and
it prints '0x1234 (nil)'

#include <stdio.h>
#include <stdlib.h>
#undef NULL
#define NULL (void*)0x1234

int main()
{
int *pt1=NULL;
int *pt2=(int*)0;

printf("%p %p\n",pt1,pt2);

return 0;
}
--
Devaraja (Xdevaraja87^gmail^c0mX)
Linux Registerd User #338167
http://counter.li.org
Nov 15 '05 #5

P: n/a
DevarajA <no@spam.com> wrote:
Eric Laberge ha scritto:
Kenneth Brody wrote: <snip>
Side question: what happens on platforms where NULL is not all-bits-
zero?
<snip> NULL is implementation-defined, but (6.3.2.3 Pointers) an integer constant
with value 0 is the same as NULL.

I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to 0x1234.
Are you sure? I've just compiled (gcc) and executed the code below, and
it prints '0x1234 (nil)'

#include <stdio.h>
#include <stdlib.h>
#undef NULL
#define NULL (void*)0x1234


Undefined behaviour, anything can happen.

Changing the definition of the NULL macro to one that yields an
arbitrarily chosen value on does not change the general behaviour
of the implementation itself.
However, nothing and nobody stops you from writing an implementation
which uses 0x1234 as the numerical value for each and any null
pointer. You just have to make sure it's different from any valid
object pointer (unlike above).
int main()
Better: int main(void)
{
int *pt1=NULL;
int *pt2=(int*)0;

printf("%p %p\n",pt1,pt2);
The %p format specifier expects an argument of type pointer-to-void.
return 0;
}


Regards.
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
clc frequent answers: http://benpfaff.org/writings/clc.
Nov 15 '05 #6

P: n/a
DevarajA wrote:
Eric Laberge ha scritto:
<snip>
Both "NULL" and "offsetof" are defined in <stddef.h> (7.17 Common
de?nitions
<stddef.h>).

NULL is implementation-defined, but (6.3.2.3 Pointers) an integer
constant with value 0 is the same as NULL.
No, a constant expression in the *source* code used in a pointer context
is a null pointer constant. However, that has no bearing on how a null
pointer is represented in the program when it is run.
I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to
0x1234.


No, NULL has to be and integer constant expression evaluating to 0 or
such an expression cast to void*. However, if a null pointer is not all
bits 0 then the compiler will have to change it to whatever
representation is used for a null pointer when it compiles the code.

Equally, a float or double value of 0 does not have to be represented by
all bits 0.
Are you sure? I've just compiled (gcc) and executed the code below, and
it prints '0x1234 (nil)'

#include <stdio.h>
#include <stdlib.h>
#undef NULL
#define NULL (void*)0x1234
You are not the implementation, so you have not changed the
representation of a null pointer constant.
int main()
{
int *pt1=NULL;
int *pt2=(int*)0;

printf("%p %p\n",pt1,pt2);
%p is for void* pointers not other pointer types. They can be
represented differently.

return 0;
}


The reason the offsetof macro can make use of a null pointer in strange
ways is that it is part of the *implementation* and the implementer is
allowed to use whatever magic s/he wants as long as it produces the
correct result. User code can't portably use such tricks.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Nov 15 '05 #7

P: n/a
Flash Gordon ha scritto:
DevarajA wrote:
Eric Laberge ha scritto:

<snip>
Both "NULL" and "offsetof" are defined in <stddef.h> (7.17 Common
de?nitions
<stddef.h>).

NULL is implementation-defined, but (6.3.2.3 Pointers) an integer
constant with value 0 is the same as NULL.

No, a constant expression in the *source* code used in a pointer context
is a null pointer constant. However, that has no bearing on how a null
pointer is represented in the program when it is run.
I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to
0x1234.

No, NULL has to be and integer constant expression evaluating to 0 or
such an expression cast to void*. However, if a null pointer is not all
bits 0 then the compiler will have to change it to whatever
representation is used for a null pointer when it compiles the code.


So, tell me if I have understood... null pointer constant needs not to
have an all-0 internal representation (it is implementation-defined),
but in the source code it must be represented as 0. And NULL macro just
expands into the null pointer constant, but I may also redefine it. Am I
right?

--
Devaraja (Xdevaraja87^gmail^c0mX)
Linux Registerd User #338167
http://counter.li.org
Nov 15 '05 #8

P: n/a
On Thu, 08 Sep 2005 15:11:27 GMT, Simon Morgan <si***@16hz.net> wrote
in comp.lang.c:
Hi,

Can somebody please help me grok the offsetof() macro?

I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?

Thanks.

Simon


The offsetof() macro is "special", as are many other things in the
standard C library and implementation. Just for example, the fopen()
function cannot itself be written in standard, portable C. It must
either interface with a lower-level API function provided by the
platform's operating system, or it must contain non-standard, hardware
specific code of its own to access a device that stores files.

Let's start with an example:

struct xyz { int x; int y; int z; };
The point is that once the compiler has processed the definition of a
structure type, it knows the offset of each of the members of the
structure. Once a human being (describes most programmers) has read
the structure definition, they know the offset of the first member,
'x', because it is at offset 0. They can guess or assume the offsets
of 'y' and 'z', but they can't really know.

There are times when it is quite useful to know the offset of a member
of a structure from the beginning of the structure. And the compiler
already has this information. So what we need is a way to write
source code that allows the compiler to provide this information to a
program when the program needs it.

Now, given our example definition, above, let's see how we can get the
offset of 'z' in a C program without using the offsetof() macro:

#include <stdio.h>
#include <stddef.h>

struct xyz { int x; int y; int z; };

int main(void)
{
struct xyz x_y_z = { 0 };
struct xyz *xyz_ptr = &x_y_z;
int *ip = &x_y_z.z;
ptrdiff_t diff = (char *)ip - (char *)xyz_ptr;
printf("%d\n", (int)diff);
return 0;
}

This is all perfectly valid, legal C code. You can cast any valid
pointer to any type of object to a pointer to char, and it will point
to the same address in memory as the lowest addressed byte of the
object. You can subtract two pointers of the same type, as long as
they both point within the same object. The result of the valid
subtraction between two pointers of the same type is the signed
integer type ptrdif_t, defined in <stddef.h>. Note that the
offsetof() macro is defined as yielding a type size_t, not ptrdif_t,
but that's a simple cast.

But to do this, we used an actual struct xyz object. What if we want
to do this without having one handy?

So let's try another version of the program which works with a pointer
to a struct xyz:

#include <stdio.h>
#include <stddef.h>

struct xyz { int x; int y; int z; };

size_t my_offsetof(struct xyz *xyz_ptr)
{
size_t result =
(size_t)((char *)&xyz_ptr->z - (char *)xyz_ptr);
return result;
}

int main(void)
{
struct xyz x_y_z = { 0 };
printf("%d\n", (int)my_offsetof(&x_y_z));
return 0;
}

This produces the same result, which happens to be 8 on the particular
compiler that I am using. But note that even though the function
my_offsetof() does not define and create a struct xyz object, the
caller must have one handy to provide a pointer to the function.

If we want to do this without having a struct xyz object anywhere, we
could be tempted to change this line in main() from:

printf("%d\n", (int)my_offsetof(&x_y_z));

....to:

printf("%d\n", (int)my_offsetof(0));

....and on many compilers this will work just fine, and perhaps on some
few it will crash the program or produce unpredictable results. That
is because passing 0 or the macro NULL causes my_offsetof() to be
called with a null pointer. And the highlighted subexpression:

(size_t)((char *)&xyz_ptr->z - (char *)xyz_ptr);
^^^^^^^^^^

....dereferences that null pointer, although in actuality the compiler
does not need to dereference the pointer, since the value of
xyz_ptr->z is not used.

So on implementations where the compiler writer knows that his
compiler will not generate code to dereference the pointer, he can
define offsetof(s,m) like this:

#define offset(s, m) ((size_t)&((s *)0)->m)

....or something similar.

This code is not legal for you to write, but the implementer is not
constrained by the rules that apply to legal programs. The
implementer is allowed to bend or break the rules in standard library
functions and macros, so long as they deliver the proper results.

On the other hand, there are some compilers that do it differently. I
have seen definitions that look like this:

#define offset(s, m) __builtin_offset__(s, m)

....that cause the compiler to look up the results in its symbol table
directly without going through the clumsy and technically undefined
operation on a null pointer.

The point is that there is a well-defined and perfectly legal sequence
that works properly on all compilers to get this information if there
is an object of the structure type available, but there is no legal,
defined method to get it without such an object. If there were, there
would have been no need for the language standard to require that the
implementation provides the macro.

So the point is, use the macro instead of trying to do the
calculations yourself. Even if you have an object of the type around,
the expression:

offsetof(struct xyz, z)

....is much more readable in your source code than:

(char *)&x_y_z->z - (char *)&x_y_z

....and the name of the macro makes the reason for its use
self-documenting.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
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
Nov 15 '05 #9

P: n/a
In article <jY*********************@news4.tin.it>,
DevarajA <no@spam.com> wrote:
So, tell me if I have understood... null pointer constant needs not to
have an all-0 internal representation (it is implementation-defined),
Right.
but in the source code it must be represented as 0.
The standard does not preclude other source-code representations, but 0
is the only portable one.
And NULL macro just
expands into the null pointer constant, but I may also redefine it. Am I
right?


It falls into the class of being reserved if any of the standard headers
are included.
--
Daylight is a trademark of OSRAM SYLVANIA INC.
Nov 15 '05 #10

P: n/a
DevarajA <no@spam.com> writes:
Flash Gordon ha scritto:
DevarajA wrote:
Eric Laberge ha scritto:

<snip>
Both "NULL" and "offsetof" are defined in <stddef.h> (7.17 Common
de?nitions
<stddef.h>).

NULL is implementation-defined, but (6.3.2.3 Pointers) an integer
constant with value 0 is the same as NULL.

No, a constant expression in the *source* code used in a pointer
context is a null pointer constant. However, that has no bearing on
how a null pointer is represented in the program when it is run.
I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to
0x1234.

No, NULL has to be and integer constant expression evaluating to 0
or such an expression cast to void*. However, if a null pointer is
not all bits 0 then the compiler will have to change it to whatever
representation is used for a null pointer when it compiles the code.


So, tell me if I have understood... null pointer constant needs not to
have an all-0 internal representation (it is implementation-defined),
but in the source code it must be represented as 0. And NULL macro
just expands into the null pointer constant, but I may also redefine
it. Am I right?


Close.

A "null pointer" and a "null pointer constant" are two different
things. A null pointer constant is a construct that can appear in C
source code. A null pointer is a pointer value that can occur during
execution time.

An integer constant 0 is a valid null pointer constant. If you assign
a null pointer constant to a pointer object, that object's value at
execution time will be a null pointer. The execution-time
representation of a null pointer may or may not be all-bits-zero. (If
a null pointer has a representation other than all-bits-zero, it's up
to the compiler to do whatever conversion might be necessary.)

The macro NULL expands to a null pointer constant. You cannot legally
redefine NULL yourself. Your compiler might let you get away with it,
but there's absolutely no reason to do so.

--
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.
Nov 15 '05 #11

P: n/a
ro******@ibd.nrc-cnrc.gc.ca (Walter Roberson) writes:
In article <jY*********************@news4.tin.it>,
DevarajA <no@spam.com> wrote:
So, tell me if I have understood... null pointer constant needs not to
have an all-0 internal representation (it is implementation-defined),


Right.
but in the source code it must be represented as 0.


The standard does not preclude other source-code representations, but 0
is the only portable one.


(See my other followup for a discussion of the distinction between
"null pointer constants" and "null pointers".)

The standard defined a "null pointer constant" as

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

So the following are all valid null pointer constants under any
possible conforming implementation:

0
(void*)0
(1-1)
(void*)('-'-'-')
(void*)('/'/'/'-'/'/'/')

All but the first two are considered silly, but they're no less valid
for that.

--
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.
Nov 15 '05 #12

P: n/a
In article <ln************@nuthaus.mib.org>,
Keith Thompson <ks***@mib.org> wrote:
So the following are all valid null pointer constants under any
possible conforming implementation: 0
(void*)0
(1-1)
(void*)('-'-'-')
(void*)('/'/'/'-'/'/'/')
That's sick!

I like it ;-)
All but the first two are considered silly, but they're no less valid
for that.

--
"Who Leads?" / "The men who must... driven men, compelled men."
"Freak men."
"You're all freaks, sir. But you always have been freaks.
Life is a freak. That's its hope and glory." -- Alfred Bester, TSMD
Nov 15 '05 #13

P: n/a
Keith Thompson ha scritto:
DevarajA <no@spam.com> writes:
Flash Gordon ha scritto:
DevarajA wrote:
Eric Laberge ha scritto:

<snip>

>Both "NULL" and "offsetof" are defined in <stddef.h> (7.17 Common
>de?nitions
><stddef.h>).
>
>NULL is implementation-defined, but (6.3.2.3 Pointers) an integer
>constant with value 0 is the same as NULL.

No, a constant expression in the *source* code used in a pointer
context is a null pointer constant. However, that has no bearing on
how a null pointer is represented in the program when it is run.
>I suppose if, eg. the implementation decided that the value of NULL is
>0x1234, then constant 0, when used as a pointer, would be equal to
>0x1234.

No, NULL has to be and integer constant expression evaluating to 0
or such an expression cast to void*. However, if a null pointer is
not all bits 0 then the compiler will have to change it to whatever
representation is used for a null pointer when it compiles the code.


So, tell me if I have understood... null pointer constant needs not to
have an all-0 internal representation (it is implementation-defined),
but in the source code it must be represented as 0. And NULL macro
just expands into the null pointer constant, but I may also redefine
it. Am I right?

Close.

A "null pointer" and a "null pointer constant" are two different
things. A null pointer constant is a construct that can appear in C
source code. A null pointer is a pointer value that can occur during
execution time.

An integer constant 0 is a valid null pointer constant. If you assign
a null pointer constant to a pointer object, that object's value at
execution time will be a null pointer. The execution-time
representation of a null pointer may or may not be all-bits-zero. (If
a null pointer has a representation other than all-bits-zero, it's up
to the compiler to do whatever conversion might be necessary.)

The macro NULL expands to a null pointer constant. You cannot legally
redefine NULL yourself. Your compiler might let you get away with it,
but there's absolutely no reason to do so.


Then using NULL is the same as using 0? So why in C many people use
NULL? Is that to avoid portability problems (in the case of a weird
non-standard implementation that has the null ptr const !=0)?

--
Devaraja (Xdevaraja87^gmail^c0mX)
Linux Registerd User #338167
http://counter.li.org
Nov 15 '05 #14

P: n/a
DevarajA <no@spam.com> writes:
Keith Thompson ha scritto:

[...]
A "null pointer" and a "null pointer constant" are two different
things. A null pointer constant is a construct that can appear in
C source code. A null pointer is a pointer value that can occur
during execution time. An integer constant 0 is a valid null
pointer constant. If you assign a null pointer constant to a
pointer object, that object's value at execution time will be a
null pointer. The execution-time representation of a null pointer
may or may not be all-bits-zero. (If a null pointer has a
representation other than all-bits-zero, it's up to the compiler to
do whatever conversion might be necessary.) The macro NULL expands
to a null pointer constant. You cannot legally redefine NULL
yourself. Your compiler might let you get away with it, but
there's absolutely no reason to do so.


Then using NULL is the same as using 0? So why in C many people use
NULL? Is that to avoid portability problems (in the case of a weird
non-standard implementation that has the null ptr const !=0)?


The advantage of using NULL is documentation. It makes it obvious
that what's intended is a pointer value, not an integer value.

For example:

a = 0;
b = 0.0;
c = '\0';
d = NULL;

You can tell even without looking at the declarations (assuming a sane
programmer) that a is an integer, b is a floating-point variable, c is
a character, and d is a pointer.

There are those who advocate using 0 rather than the NULL macro as a
null pointer constant. They are, of course, wrong, since they
disagree with me.

(If I were designing the language from scratch, there would be a
keyword, either "nil" or "null", that would be the *only* null pointer
constant. Using 0 in a pointer context would be a constraint error.
The current confusing situation is, I think, a remnant of the early
days of C when it was assumed that a null pointer *was* all-bits-zero,
and even non-zero integer constants were commonly used as pointers.)

--
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.
Nov 15 '05 #15

P: n/a
>
There are those who advocate using 0 rather than the NULL macro as a
null pointer constant. They are, of course, wrong, since they
disagree with me.

(If I were designing the language from scratch, there would be a
keyword, either "nil" or "null", that would be the *only* null pointer
constant. Using 0 in a pointer context would be a constraint error.


What do you mean by "using 0 in a pointer context"? In another post you
have said "An integer constant 0 is a valid null pointer constant. If
you assign a null pointer constant to a pointer object, that object's
value at execution time will be a null pointer."+"The macro NULL expands
to a null pointer constant." And now you say that using 0 is a
constraint error. I think I haven't understood yet :-(

And on every compiler I've tried, int *pt=0; works without errors or
warnigs. And also the standard says that a constant expression
evaluating to 0 or such an expression cast to void*, assigned to a
pointer of wathever type makes it a null pointer.

Sorry if I'm wasting your time, but I'm a bit confused...

--
Devaraja (Xdevaraja87^gmail^c0mX)
Linux Registerd User #338167
http://counter.li.org
Nov 15 '05 #16

P: n/a
DevarajA <no@spam.com> wrote:

[DevarajA: please preserve attribution lines, to make clear who wrote
what. Attribution restored.]
Keith Thompson wrote:
There are those who advocate using 0 rather than the NULL macro as a
null pointer constant. They are, of course, wrong, since they
disagree with me.
:-)
(If I were designing the language from scratch, there would be a
keyword, either "nil" or "null", that would be the *only* null pointer
constant. Using 0 in a pointer context would be a constraint error.


What do you mean by "using 0 in a pointer context"? In another post you
have said "An integer constant 0 is a valid null pointer constant. If
you assign a null pointer constant to a pointer object, that object's
value at execution time will be a null pointer."+"The macro NULL expands
to a null pointer constant." And now you say that using 0 is a
constraint error. I think I haven't understood yet :-(


Please read again: Keith _would_make_ using 0 in a pointer context a
constraint violation, _if_he_were_re-designing_the_language_C_.

C-as-we-know-it: int *p = 0; /* correct, but bad style */
Keith's revamped C: int *p = 0; /* constraint violation */

(FWIW, I'd probably do the same.)

<snip>

Best regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
clc frequent answers: http://benpfaff.org/writings/clc.
Nov 15 '05 #17

P: n/a
Irrwahn Grausewitz ha scritto:
DevarajA <no@spam.com> wrote:

[DevarajA: please preserve attribution lines, to make clear who wrote
what. Attribution restored.]

Keith Thompson wrote:
There are those who advocate using 0 rather than the NULL macro as a
null pointer constant. They are, of course, wrong, since they
disagree with me.

:-)

(If I were designing the language from scratch, there would be a
keyword, either "nil" or "null", that would be the *only* null pointer
constant. Using 0 in a pointer context would be a constraint error.
What do you mean by "using 0 in a pointer context"? In another post you
have said "An integer constant 0 is a valid null pointer constant. If
you assign a null pointer constant to a pointer object, that object's
value at execution time will be a null pointer."+"The macro NULL expands
to a null pointer constant." And now you say that using 0 is a
constraint error. I think I haven't understood yet :-(

Please read again: Keith _would_make_ using 0 in a pointer context a
constraint violation, _if_he_were_re-designing_the_language_C_.


Ok, got it :-) thank you all.
C-as-we-know-it: int *p = 0; /* correct, but bad style */
Keith's revamped C: int *p = 0; /* constraint violation */


Another thing.. looking into stddef.h I've seen that for C, NULL it is
defined as ((void*)0). The standard specifies that plain 0 is already a
null pointer constant. So why that cast? Maybe this is the last stupid
question for today :-)

--
Devaraja (Xdevaraja87^gmail^c0mX)
Linux Registerd User #338167
http://counter.li.org
Nov 15 '05 #18

P: n/a
DevarajA <no@spam.com> writes:
There are those who advocate using 0 rather than the NULL macro as a
null pointer constant. They are, of course, wrong, since they
disagree with me.
(If I were designing the language from scratch, there would be a
keyword, either "nil" or "null", that would be the *only* null pointer
constant. Using 0 in a pointer context would be a constraint error.


What do you mean by "using 0 in a pointer context"? In another post
you have said "An integer constant 0 is a valid null pointer
constant. If you assign a null pointer constant to a pointer object,
that object's value at execution time will be a null pointer."+"The
macro NULL expands to a null pointer constant." And now you say that
using 0 is a constraint error. I think I haven't understood yet :-(


Look again. I said that if I were designing the language from
scratch, using 0 in a pointer context would be a constraint error (I
meant "constraint violation"). In C as it actually exists, 0 is a
valid null pointer constant, so it *can* be used in a pointer context.

For example:

int *p;
p = 0;

This is perfectly legal C. As a matter of style and clarity, I
prefer:

int *p;
p = NULL;

(In my hypothetical, non-existent C-like language, there would be a
keyword "nil" that would be the only legal null pointer constant.
"p = 0;" would be illegal, and there would be no need for the NULL
macro. I occasionally rant about how I'd redesign C if I had the
chance; don't take it too seriously.)

--
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.
Nov 15 '05 #19

P: n/a
DevarajA <no@spam.com> wrote:
<snip>
Another thing.. looking into stddef.h I've seen that for C, NULL it is
defined as ((void*)0).
Depends on the implementation, yours happen to use the above
definition, another might define NULL as (0) or even
((void *)('9'-'4'-'5')).
The standard specifies that plain 0 is already a
null pointer constant. So why that cast?
I'm just guessing now; maybe the implementer thought: while we all
know that it's perfectly legitimate to implicitly convert a constant
integer expression with value 0 to any type of pointer, yielding a
null pointer of that type, I'll take a step further and _explicitly_
spell it out as ((void *)0) in the definition of the NULL macro.

Like saying: "Yes, I _really_ _really_ mean null pointer constant."

For a definite answer you'd have to ask the guy himself. ;o)
Maybe this is the last stupid
question for today :-)


There are no stupid questions, only stupid answers. :-)

Best regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
clc frequent answers: http://benpfaff.org/writings/clc.
Nov 15 '05 #20

P: n/a
DevarajA <no@spam.com> writes:
[...]
Another thing.. looking into stddef.h I've seen that for C, NULL it is
defined as ((void*)0). The standard specifies that plain 0 is already
a null pointer constant. So why that cast? Maybe this is the last
stupid question for today :-)


No, looking into the stddef.h header for your implementation tells you
how your implementation defines NULL. Another implementation could
define it as 0.

The standard says that a null pointer constant is "An integer constant
expression with the value 0, or such an expression cast to type void *",
and that NULL is a macro that "expands to an implementation-defined
null pointer constant".

One advantage of defining NULL as ((void*)0) rather than as 0 is that
it can catch some errors. A constant 0, though it's a null pointer
constant, can also be used in a non-pointer context; ((void*)0)
cannot. For example, I've seen code that incorrectly uses NULL to
denote a null character:
char s[50];
s[0] = NULL;
If NULL is defined as 0, this won't be diagnosed. If it's defined as
((void*)0), it will be.

Please ignore the remainder of this message.

There's actually some doubt about whether ((void*)0) is a legal
definition for NULL. The standard says that a constant 0 cast to
void* is a null pointer constant. It doesn't say that a constant 0
cast to void* *and enclosed in parentheses* is a null pointer
constant. C99 6.5.1 says a parenthesized expression "is an lvalue, a
function designator, or a void expression if the unparenthesized
expression is, respectively, an lvalue, a function designator, or a
void expression"; it doesn't say that a parenthesized expression is a
null pointer constant if the unparenthesized expression is a null
pointer constant.

This is nothing more than a minor glitch in the wording of the
standard, of no real significance either to programmers or to
implementers.

--
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.
Nov 15 '05 #21

P: n/a
DevarajA wrote:

<snip>
Another thing.. looking into stddef.h I've seen that for C, NULL it is
defined as ((void*)0). The standard specifies that plain 0 is already a
null pointer constant. So why that cast? Maybe this is the last stupid
question for today :-)


The C standard allows the implementation to include the case, and the
reason that some implementations do so is to prevent you from using NULL
in an integer context. So on your implementation the following are all
constraint violations because pointers are not automatically converted
to numbers:

char c = NULL;
int i = NULL;
float f = NULL;
double d = NULL;

However, on an implementation where NULL is defined as plain 0 (which
the standard allows) all of the above are legal even though to a human
reader they don't make sense.

One reason people do mistakenly assign NULL to char variables (or
elements of char arrays) is because the ASCII character set (which C
does not mandate) calls character '\0' NUL and the C standard I believe
calls it a null character, so it is easy to get it confused with NULL.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Nov 15 '05 #22

P: n/a
In article <q9********************************@4ax.com>,
Irrwahn Grausewitz <ir*******@freenet.de> wrote:
Depends on the implementation, yours happen to use the above
definition, another might define NULL as (0) or even
((void *)('9'-'4'-'5')).


That would only be equivilent to 0 in the rather unusual case
that the representation of the digits started from 0 instead of
(e.g.) ASCII's 48.

Perhaps you meant ((void *)('9'-'4'-5))

--
'The short version of what Walter said is "You have asked a question
which has no useful answer, please reconsider the nature of the
problem you wish to solve".' -- Tony Mantler
Nov 15 '05 #23

P: n/a
Irrwahn Grausewitz wrote:

DevarajA <no@spam.com> wrote:

[...]
Maybe this is the last stupid
question for today :-)


There are no stupid questions, only stupid answers. :-)


You've obviously never hung around ASR and ATSR, have you? They'll give
you plently of "stupid question" examples. :-)

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:Th*************@gmail.com>
Nov 15 '05 #24

P: n/a
DevarajA wrote:
[...]
Another thing.. looking into stddef.h I've seen that for C, NULL it is
defined as ((void*)0). The standard specifies that plain 0 is already a
null pointer constant. So why that cast? Maybe this is the last stupid
question for today :-)


Probably to explicitly make it a pointer.

That, and to give warnings when someone does:

char *pt;
...
while ( *pt != NULL )
...

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:Th*************@gmail.com>
Nov 15 '05 #25

P: n/a
ro******@ibd.nrc-cnrc.gc.ca (Walter Roberson) wrote:
In article <q9********************************@4ax.com>,
Irrwahn Grausewitz <ir*******@freenet.de> wrote:
Depends on the implementation, yours happen to use the above
definition, another might define NULL as (0) or even
((void *)('9'-'4'-'5')).


That would only be equivilent to 0 in the rather unusual case
that the representation of the digits started from 0 instead of
(e.g.) ASCII's 48.

Perhaps you meant ((void *)('9'-'4'-5))


Umm... something like that... brain fart on my side...
me dumba, he he. :)

Thanks for pointing out & best regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
clc frequent answers: http://benpfaff.org/writings/clc.
Nov 15 '05 #26

P: n/a
On Thu, 08 Sep 2005 15:11:27 +0000, Simon Morgan wrote:
Can somebody please help me grok the offsetof() macro?


Thank you all for the excellent explanations, they were most helpful.

--
"Being a social outcast helps you stay concentrated on the really important
things, like thinking and hacking." - Eric S. Raymond

Nov 15 '05 #27

P: n/a
Keith Thompson <ks***@mib.org> writes:
DevarajA <no@spam.com> writes:
Keith Thompson ha scritto: [...]
A "null pointer" and a "null pointer constant" are two different
things. A null pointer constant is a construct that can appear in
C source code. A null pointer is a pointer value that can occur
during execution time. An integer constant 0 is a valid null
pointer constant. If you assign a null pointer constant to a
pointer object, that object's value at execution time will be a
null pointer. The execution-time representation of a null pointer
may or may not be all-bits-zero. (If a null pointer has a
representation other than all-bits-zero, it's up to the compiler to
do whatever conversion might be necessary.) The macro NULL expands
to a null pointer constant. You cannot legally redefine NULL
yourself. Your compiler might let you get away with it, but
there's absolutely no reason to do so.


Then using NULL is the same as using 0? So why in C many people use
NULL? Is that to avoid portability problems (in the case of a weird
non-standard implementation that has the null ptr const !=0)?


The advantage of using NULL is documentation. It makes it obvious
that what's intended is a pointer value, not an integer value.

For example:

a = 0;
b = 0.0;
c = '\0';
d = NULL;

You can tell even without looking at the declarations (assuming a sane
programmer) that a is an integer, b is a floating-point variable, c is
a character, and d is a pointer.


A complaint I have about NULL is that NULL isn't guaranteed to be
a pointer. Supplying NULL as a trailing argument (corresponding
to a post-ellipsis parameter), for example, isn't guaranteed to
pass a pointer rather than an int 0. It would be nice if the
Standard were changed to fix this.
[snip] The current confusing situation is, I think, a remnant of the early
days of C when it was assumed that a null pointer *was* all-bits-zero,
and even non-zero integer constants were commonly used as pointers.


Perhaps partly, but there's another factor that may play a larger
role here. C deliberately proclaimed null pointers as zero and
non-null pointers as non-zero, so that they would work nicely
with if's and while's. People who learned C later seem to like
explicit comparisons (whether to NULL or 0); "old timers" are
more used to seeing things like

if(p) ...
if(!p) ...

and may even prefer them. For these forms, it's convenient to
think of null pointers as being all-bits-zero, even if in the
back of the mind it's known not to always be true.
Nov 15 '05 #28

P: n/a
Keith Thompson <ks***@mib.org> writes:
There's actually some doubt about whether ((void*)0) is a legal
definition for NULL. The standard says that a constant 0 cast to
void* is a null pointer constant. It doesn't say that a constant 0
cast to void* *and enclosed in parentheses* is a null pointer
constant. C99 6.5.1 says a parenthesized expression "is an lvalue, a
function designator, or a void expression if the unparenthesized
expression is, respectively, an lvalue, a function designator, or a
void expression"; it doesn't say that a parenthesized expression is a
null pointer constant if the unparenthesized expression is a null
pointer constant.


Whatever NULL is defined as seems like it must be a null pointer
constant, by definition. Per 7.17 p3, NULL "expands to an
implementation-defined null pointer constant". So even if we had

#define NULL the rain in Spain falls mainly on the plain

it would be (defined by the implementation as) a null pointer
constant. It's just up to the other parts of the implementation
to insure that it behaves as one.

Is it true that, except for function pointers, it's unnecessary
to have '(void*) <constant-zero-expression>' be defined as a
null pointer constant?
Nov 15 '05 #29

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
Whatever NULL is defined as seems like it must be a null pointer
constant, by definition. Per 7.17 p3, NULL "expands to an
implementation-defined null pointer constant". So even if we had

#define NULL the rain in Spain falls mainly on the plain

it would be (defined by the implementation as) a null pointer
constant. It's just up to the other parts of the implementation
to insure that it behaves as one.
IOW: the implementation has to take care that
the rain in Spain falls mainly on the plain
is treated as an integer constant expression with the value 0,
possibly cast to void * (see below). Ugly, but IMHO feasible.
But ugly. Did I already mention ugly?
Is it true that, except for function pointers, it's unnecessary
to have '(void*) <constant-zero-expression>' be defined as a
null pointer constant?


In which aspect are function pointers different? Consider:

ISO/IEC 9899:1999 (E)
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.
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.

6.5.16.1
1 One of the following shall hold:
[...]
— the left operand is a pointer and the right is a null pointer
constant
[...]
2 In simple assignment (=), the value of the right operand is
converted to the type of the assignment expression and replaces the
value stored in the object designated by the left operand.

Did I miss anything important?

Best Regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
clc frequent answers: http://benpfaff.org/writings/clc
Nov 15 '05 #30

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
[...]
A complaint I have about NULL is that NULL isn't guaranteed to be
a pointer. Supplying NULL as a trailing argument (corresponding
to a post-ellipsis parameter), for example, isn't guaranteed to
pass a pointer rather than an int 0. It would be nice if the
Standard were changed to fix this.


Changed how, exactly? Even if you required NULL to be defined as,
say, ((void*)0), it would evaluate to a null pointer of type void*,
which could still cause problems if you need a null pointer of some
other pointer type as an argument to a function with a variable number
of arguments. Yes, ((void*)0) does catch some errors that 0 doesn't,
but you still need to use (foo*)NULL rather than just NULL in some
cases.

Now if I were designing the language from scratch, "nil" would be a
keyword that would evaluate to a null pointer of whatever type is
implied by the context. If the context didn't imply a particular
pointer type, a cast would be required.

--
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.
Nov 15 '05 #31

P: n/a
ro******@ibd.nrc-cnrc.gc.ca (Walter Roberson) wrote:
In article <q9********************************@4ax.com>,
Irrwahn Grausewitz <ir*******@freenet.de> wrote:
Depends on the implementation, yours happen to use the above
definition, another might define NULL as (0) or even
((void *)('9'-'4'-'5')).


That would only be equivilent to 0 in the rather unusual case
that the representation of the digits started from 0 instead of
(e.g.) ASCII's 48.


Which is actually not allowed, since that would mean '0' would be the
string-terminating null character.

Richard
Nov 15 '05 #32

P: n/a
Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
[...]
A complaint I have about NULL is that NULL isn't guaranteed to be
a pointer. Supplying NULL as a trailing argument (corresponding
to a post-ellipsis parameter), for example, isn't guaranteed to
pass a pointer rather than an int 0. It would be nice if the
Standard were changed to fix this.
Changed how, exactly? Even if you required NULL to be defined as,
say, ((void*)0), it would evaluate to a null pointer of type void*,
which could still cause problems if you need a null pointer of some
other pointer type as an argument to a function with a variable number
of arguments. Yes, ((void*)0) does catch some errors that 0 doesn't,
but you still need to use (foo*)NULL rather than just NULL in some
cases.


For example, adding a statement that says NULL will always
evaluate to some pointer type would be an improvement. I agree
that there are cases where casts would need to be added, such as
the one you mention. But casts are going to be needed in some
cases in any event. Requiring NULL to evaluate to some pointer
type would lessen the number of such cases, and as a practical
matter would tend to produce better behavior in cases where casts
were needed but left out.

On the flip side, I don't see any benefit in allowing NULL to
evaluate to an integer type rather than a pointer type, as the
current language does.

Now if I were designing the language from scratch, "nil" would be a
keyword that would evaluate to a null pointer of whatever type is
implied by the context. If the context didn't imply a particular
pointer type, a cast would be required.


In effect that's what I'm suggesting, with these changes: one,
the language element be a macro rather than a keyword; two, the
language element be spelled "NULL" rather than "nil"; three, if
context doesn't imply a particular pointer type, 'void *' is the
type that results. I don't mean to claim that one approach is
better than the other, only that the two suggestions are not that
different from each other.
Nov 15 '05 #33

P: n/a
Irrwahn Grausewitz <ir*******@freenet.de> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
Whatever NULL is defined as seems like it must be a null pointer
constant, by definition. Per 7.17 p3, NULL "expands to an
implementation-defined null pointer constant". So even if we had

#define NULL the rain in Spain falls mainly on the plain

it would be (defined by the implementation as) a null pointer
constant. It's just up to the other parts of the implementation
to insure that it behaves as one.


IOW: the implementation has to take care that
the rain in Spain falls mainly on the plain
is treated as an integer constant expression with the value 0,
possibly cast to void * (see below).


That's a way of reading it; however, it isn't what I meant to
suggest. Rather, we can read 7.17 p3 as saying that whatever
NULL is defined as is a null pointer constant, regardless of
whether it involves the integer value 0 (constant or otherwise),
and regardless of whether it involves casting to 'void *'. In
other words, the exansion for NULL is a null pointer constant
because 7.17 p3 stipulates that it is. The expressions '0' and
'(void*) 0' are null pointer constants, because 6.3.2.3 says they
are; however, an implementation is free to define other
expressions as null pointer constants -- such as for example

(void*)(char*)(void*)0

and whatever NULL expands to is one such implementation-defined
null pointer constant.
Is it true that, except for function pointers, it's unnecessary
to have '(void*) <constant-zero-expression>' be defined as a
null pointer constant?


In which aspect are function pointers different? Consider:

ISO/IEC 9899:1999 (E)
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.
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.

6.5.16.1
1 One of the following shall hold:
[...]
— the left operand is a pointer and the right is a null pointer
constant
[...]
2 In simple assignment (=), the value of the right operand is
converted to the type of the assignment expression and replaces the
value stored in the object designated by the left operand.

Did I miss anything important?


Consider:

int (*function_pointer_1)( int ) = (void*) 0;
int (*function_pointer_2)( int ) = (char*) 0;

The first of these declarations is ok, the other is a type error.
The first declaration works only because '(void*) 0' is a null
pointer constant, and it's allowed to assign a null pointer
constant to a function pointer. Assigning an expression of type
'void *', but not a null pointer constant, to a function pointer
is not allowed.

So if '(void*) 0' were not a null pointer constant, then the
first declaration wouldn't work (because the initializing
expression exhibits a type mismatch).
Nov 15 '05 #34

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
[...]
> A complaint I have about NULL is that NULL isn't guaranteed to be
> a pointer. Supplying NULL as a trailing argument (corresponding
> to a post-ellipsis parameter), for example, isn't guaranteed to
> pass a pointer rather than an int 0. It would be nice if the
> Standard were changed to fix this.


Changed how, exactly? Even if you required NULL to be defined as,
say, ((void*)0), it would evaluate to a null pointer of type void*,
which could still cause problems if you need a null pointer of some
other pointer type as an argument to a function with a variable number
of arguments. Yes, ((void*)0) does catch some errors that 0 doesn't,
but you still need to use (foo*)NULL rather than just NULL in some
cases.


For example, adding a statement that says NULL will always
evaluate to some pointer type would be an improvement. I agree
that there are cases where casts would need to be added, such as
the one you mention. But casts are going to be needed in some
cases in any event. Requiring NULL to evaluate to some pointer
type would lessen the number of such cases, and as a practical
matter would tend to produce better behavior in cases where casts
were needed but left out.

On the flip side, I don't see any benefit in allowing NULL to
evaluate to an integer type rather than a pointer type, as the
current language does.


Ok. A simpler way to express this would be to require NULL to be
defined as ((void*)0) (and to tweak the wording of the definition of
"null pointer constant" to make it clear that that's legal). I would
have no problem with that; I don't see the benefit of allowing each
implementation to decide which null pointer constant it will use in
the definition of NULL.
Now if I were designing the language from scratch, "nil" would be a
keyword that would evaluate to a null pointer of whatever type is
implied by the context. If the context didn't imply a particular
pointer type, a cast would be required.


In effect that's what I'm suggesting, with these changes: one,
the language element be a macro rather than a keyword; two, the
language element be spelled "NULL" rather than "nil"; three, if
context doesn't imply a particular pointer type, 'void *' is the
type that results. I don't mean to claim that one approach is
better than the other, only that the two suggestions are not that
different from each other.


My idea (which is totally impractical because it would break existing
code) is that the "nil" keyword would be the *only* legal null pointer
constant.

--
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.
Nov 15 '05 #35

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Irrwahn Grausewitz <ir*******@freenet.de> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
>Whatever NULL is defined as seems like it must be a null pointer
>constant, by definition. Per 7.17 p3, NULL "expands to an
>implementation-defined null pointer constant". So even if we had
>
> #define NULL the rain in Spain falls mainly on the plain
>
>it would be (defined by the implementation as) a null pointer
>constant. It's just up to the other parts of the implementation
>to insure that it behaves as one.


IOW: the implementation has to take care that
the rain in Spain falls mainly on the plain
is treated as an integer constant expression with the value 0,
possibly cast to void * (see below).


That's a way of reading it; however, it isn't what I meant to
suggest. Rather, we can read 7.17 p3 as saying that whatever
NULL is defined as is a null pointer constant, regardless of
whether it involves the integer value 0 (constant or otherwise),
and regardless of whether it involves casting to 'void *'. In
other words, the exansion for NULL is a null pointer constant
because 7.17 p3 stipulates that it is. The expressions '0' and
'(void*) 0' are null pointer constants, because 6.3.2.3 says they
are; however, an implementation is free to define other
expressions as null pointer constants -- such as for example

(void*)(char*)(void*)0

and whatever NULL expands to is one such implementation-defined
null pointer constant.


C99 6.3.2.3p3 defines the term "null pointer constant":

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

I don't see any permission for the implementation to define null
pointer constants that don't meet that definition. 7.17p3 says that
the macro NULL "expands to an implementation-defined null pointer
constant". This allows the implementation to define NULL as either 0,
(void*)0, or ('/'/'/'-'/'/'/'); it doesn't allow it to define NULL as
(void*)(char*)0. 7.17p3 constrains the implementation's definition of
NULL; it doesn't define "null pointer constant".

--
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.
Nov 15 '05 #36

P: n/a
Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes: [snip]
Now if I were designing the language from scratch, "nil" would be a
keyword that would evaluate to a null pointer of whatever type is
implied by the context. If the context didn't imply a particular
pointer type, a cast would be required.


In effect that's what I'm suggesting, with these changes: one,
the language element be a macro rather than a keyword; two, the
language element be spelled "NULL" rather than "nil"; three, if
context doesn't imply a particular pointer type, 'void *' is the
type that results. I don't mean to claim that one approach is
better than the other, only that the two suggestions are not that
different from each other.


My idea (which is totally impractical because it would break existing
code) is that the "nil" keyword would be the *only* legal null pointer
constant.


Ahh I see. The revised language would not only add 'nil' but
also would take away '0' (and '(void*)0') as a way of writing
null pointer values. Clearly there are some benefits to using
'nil' as the only form of null pointer constant. What do you
think the costs are, not counting the cost of converting existing
code so that it uses 'nil'? Or have you thought much about what
the costs would be?
Nov 15 '05 #37

P: n/a
Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Irrwahn Grausewitz <ir*******@freenet.de> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
>Whatever NULL is defined as seems like it must be a null pointer
>constant, by definition. Per 7.17 p3, NULL "expands to an
>implementation-defined null pointer constant". So even if we had
>
> #define NULL the rain in Spain falls mainly on the plain
>
>it would be (defined by the implementation as) a null pointer
>constant. It's just up to the other parts of the implementation
>to insure that it behaves as one.

IOW: the implementation has to take care that
the rain in Spain falls mainly on the plain
is treated as an integer constant expression with the value 0,
possibly cast to void * (see below).


That's a way of reading it; however, it isn't what I meant to
suggest. Rather, we can read 7.17 p3 as saying that whatever
NULL is defined as is a null pointer constant, regardless of
whether it involves the integer value 0 (constant or otherwise),
and regardless of whether it involves casting to 'void *'. In
other words, the exansion for NULL is a null pointer constant
because 7.17 p3 stipulates that it is. The expressions '0' and
'(void*) 0' are null pointer constants, because 6.3.2.3 says they
are; however, an implementation is free to define other
expressions as null pointer constants -- such as for example

(void*)(char*)(void*)0

and whatever NULL expands to is one such implementation-defined
null pointer constant.


C99 6.3.2.3p3 defines the term "null pointer constant":

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

I don't see any permission for the implementation to define null
pointer constants that don't meet that definition. 7.17p3 says that
the macro NULL "expands to an implementation-defined null pointer
constant". This allows the implementation to define NULL as either 0,
(void*)0, or ('/'/'/'-'/'/'/'); it doesn't allow it to define NULL as
(void*)(char*)0. 7.17p3 constrains the implementation's definition of
NULL; it doesn't define "null pointer constant".


I agree the issue is not clear cut. I wasn't meaning to start a
debate on the issue, only to give a plausible and reasonable
alternative reading. However, since you ask, let me frame some
arguments.

1. The Standard isn't always careful in how definitions are given.
There was discussion recently on the definition of "definition", for
example. Although I think it would be a good idea if the Standard
were more rigorous (and, dare I say it, "mathematical") in defining
and using special terms, that isn't what it does now.

2. Note the particular wording in 6.3.2.3 p3: such-and-such kind of
expression *is called* a null pointer constant. It doesn't say the
list is exhaustive. If there are any candidates for definitions in
the Standard that are one-way definitions rather than two-way
definitions, surely the statement in 6.3.2.3 p3 must be one of them.

3. The mere use of the term "implementation-defined null pointer
constants" suggests that there are some null pointer constants that
are defined by the implementation rather than by the Standard.
Otherwise, 7.17 p3 could have said just that "NULL expands to a null
pointer constant". Based on the way other parts of the Standard are
written, the more concise form seems more likely if an implementation
were not allowed to define null pointer constants (perhaps with a
footnote that says, eg, "The choice of which null pointer constant
expression to use is implementation defined.").

4. If we take 6.3.2.3 p3 as precisely delimiting the set of
expressions that are null pointer constants, then, as you yourself
pointed out, '((void*)0)' would not be a null pointer constant.
Yet

int (*fp)(int);
fp = ((void*)0);

works. (At least, I'm not aware of any implementation where it
doesn't work.) This code isn't allowed to work (without a diagnostic)
unless '((void*)0)' were a null pointer constant. So what are we to
believe? That lots of implementations got it wrong, or that the set
of expressions mentioned in 6.3.2.3 p3 is not exhaustive? The second
alternative seems more likely. If the set of expressions mentioned in
6.3.2.3 p3 is not exhaustive, then of course any additional forms of
null pointer constant would be implementation defined.

5. In the absence of any clearly compelling argument to the contrary,
the reading that puts less strain on the interpretation seems better.
Basically, Occam's Razor. Unless there is specific evidence that an
implementation is forbidden from defining particular forms of null
pointer constants, it's a better match to the observed facts to
assume that it's allowed.
Nov 15 '05 #38

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:

[...]
My idea (which is totally impractical because it would break existing
code) is that the "nil" keyword would be the *only* legal null pointer
constant.


Ahh I see. The revised language would not only add 'nil' but
also would take away '0' (and '(void*)0') as a way of writing
null pointer values. Clearly there are some benefits to using
'nil' as the only form of null pointer constant. What do you
think the costs are, not counting the cost of converting existing
code so that it uses 'nil'? Or have you thought much about what
the costs would be?


I've used other languages that have a keyword that's used as the
equivalent of a null pointer constant, and that don't allow any other
form of null pointer constant. I'll just mention that programmers in
those languages typically don't know or care how null pointers are
represented; even if they happen to know how a given implementation
represents null pointers, they don't try to make use of the knowledge.
And their FAQs don't have to devote an entire section to null
pointers.

I don't think there are any costs to this approach, apart from the
insurmountable cost of all the existing C code that would be broken.

I'm almost tempted to suggest adding a "nil" keyword to the next C
standard, with the obvious semantics, *without* eliminating the other
forms of null pointer constant. But providing a better approach
without removing the old one would just add to the confusion.

(One way to do this might be to add a declaration
enum { nil };
to <stddef.h>, and to have the compiler issue a warning if it's used
in a non-pointer context.)

--
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.
Nov 15 '05 #39

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes: [...]
C99 6.3.2.3p3 defines the term "null pointer constant":

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

I don't see any permission for the implementation to define null
pointer constants that don't meet that definition. 7.17p3 says that
the macro NULL "expands to an implementation-defined null pointer
constant". This allows the implementation to define NULL as either 0,
(void*)0, or ('/'/'/'-'/'/'/'); it doesn't allow it to define NULL as
(void*)(char*)0. 7.17p3 constrains the implementation's definition of
NULL; it doesn't define "null pointer constant".


I agree the issue is not clear cut. I wasn't meaning to start a
debate on the issue, only to give a plausible and reasonable
alternative reading. However, since you ask, let me frame some
arguments.


Actually, we aren't in agreement. I think the issue is (reasonably)
clear-cut.
1. The Standard isn't always careful in how definitions are given.
There was discussion recently on the definition of "definition", for
example. Although I think it would be a good idea if the Standard
were more rigorous (and, dare I say it, "mathematical") in defining
and using special terms, that isn't what it does now.
Agreed. However, there are cases where the standard gives explicit
permission to do something in an implementation-defined way, such as
the declaration of main(). The fact that it doesn't do so here is,
IMHO, significant.
2. Note the particular wording in 6.3.2.3 p3: such-and-such kind of
expression *is called* a null pointer constant. It doesn't say the
list is exhaustive. If there are any candidates for definitions in
the Standard that are one-way definitions rather than two-way
definitions, surely the statement in 6.3.2.3 p3 must be one of them.
Since there's a clear and unambiguous interpretation assuming the
definition is exhaustive, I believe that's the best interpretation.

The standard doesn't give explicit permission for other forms of null
pointer constant. Using (void*)42 in a context that requires a null
pointer constant is a constraint violation. An implementation that
doesn't issue a diagnostic for such a use is non-conforming.

Similarly, the standard doesn't give permission for other forms of
integer constants. An implementation can accept 0b11001001 as a
binary constant as a language extension, but it must issue a
diagnostic for any such constant in conforming mode.
3. The mere use of the term "implementation-defined null pointer
constants" suggests that there are some null pointer constants that
are defined by the implementation rather than by the Standard.
Otherwise, 7.17 p3 could have said just that "NULL expands to a null
pointer constant". Based on the way other parts of the Standard are
written, the more concise form seems more likely if an implementation
were not allowed to define null pointer constants (perhaps with a
footnote that says, eg, "The choice of which null pointer constant
expression to use is implementation defined.").
The term "implementation-defined" doesn't just mean that the
implementation gets to make a choice; it also means it has to document
that choice. If the standard merely said that NULL expands to a null
pointer constant, an implementation wouldn't be required to document
what it actually expands to. This would be no great loss, since code
shouldn't depend on the choice, but I believe the intent is that (a)
an implementation can choose any valid null pointer constant as the
expansion of NULL, and (b) it must document what choice it makes.

It wouldn't make sense to use the phrase "implementation defined" only
in a footnote.
4. If we take 6.3.2.3 p3 as precisely delimiting the set of
expressions that are null pointer constants, then, as you yourself
pointed out, '((void*)0)' would not be a null pointer constant.
Yet

int (*fp)(int);
fp = ((void*)0);

works. (At least, I'm not aware of any implementation where it
doesn't work.) This code isn't allowed to work (without a diagnostic)
unless '((void*)0)' were a null pointer constant. So what are we to
believe? That lots of implementations got it wrong, or that the set
of expressions mentioned in 6.3.2.3 p3 is not exhaustive? The second
alternative seems more likely. If the set of expressions mentioned in
6.3.2.3 p3 is not exhaustive, then of course any additional forms of
null pointer constant would be implementation defined.
I believe the glitch in 6.3.2.3p3, which implies that (void*)0 is a
null pointer constant but ((void*)0) isn't, is simply an oversight. I
suspect the authors of the standard just assumed that an expression in
parentheses is equivalent to the expression without parentheses -- and
of course enclosing macro definitions in parentheses is almost always
a good idea. Implementations actually conform to the intent of the
standard in this case, rather than to the literal wording. I wouldn't
infer anything significant from this (though I'd certainly like to see
this corrected.)
5. In the absence of any clearly compelling argument to the contrary,
the reading that puts less strain on the interpretation seems better.
Basically, Occam's Razor. Unless there is specific evidence that an
implementation is forbidden from defining particular forms of null
pointer constants, it's a better match to the observed facts to
assume that it's allowed.


I disagree. I find it much simpler to assume that the definition of
"null pointer constant" means exactly what it says, modulo the
parentheses glitch. The intent of the phrase "implementation-defined
null pointer constant" in 7.17p3 is quite clear given this
interpretation; there's no need to invent the idea of additional
implementation-defined *forms* of null pointer constant. There's also
no advantage in doing so; we have more than enough null pointer
constants already without allowing implementations to invent their
own.

--
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.
Nov 15 '05 #40

P: n/a
Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes: [...]
My idea (which is totally impractical because it would break existing
code) is that the "nil" keyword would be the *only* legal null pointer
constant.


Ahh I see. The revised language would not only add 'nil' but
also would take away '0' (and '(void*)0') as a way of writing
null pointer values. Clearly there are some benefits to using
'nil' as the only form of null pointer constant. What do you
think the costs are, not counting the cost of converting existing
code so that it uses 'nil'? Or have you thought much about what
the costs would be?


I've used other languages that have a keyword that's used as the
equivalent of a null pointer constant, and that don't allow any other
form of null pointer constant. I'll just mention that programmers in
those languages typically don't know or care how null pointers are
represented; even if they happen to know how a given implementation
represents null pointers, they don't try to make use of the knowledge.
And their FAQs don't have to devote an entire section to null
pointers.


Sure; certainly there are some benefits to the 'nil' approach.

I don't think there are any costs to this approach, apart from the
insurmountable cost of all the existing C code that would be broken.
In my experience these kinds of design choices essentially always
carry ongoing costs as well as benefits. That isn't to say that the
benefits won't outweigh the costs necessarily, only that there also
are costs to consider. So if you aren't aware of any costs besides
the cost of converting existing code, maybe you haven't considered
the ramifications fully enough yet?

To put this another way, when C was being designed, there already were
languages with, eg, NULL to indicate null pointers (and no other forms
allowed). Yet KT and/or DR decided to use 0 for null pointers, so
they must have thought there were some benefits to doing that over
using NULL. If the original C model has some benefits, then giving
those up is a cost.

I'm almost tempted to suggest adding a "nil" keyword to the next C
standard, with the obvious semantics, *without* eliminating the other
forms of null pointer constant. But providing a better approach
without removing the old one would just add to the confusion.


Why not just use NULL? A lint-like tool, or a compiler warning
switch, could be used to flag those cases where a pointer value is
needed yet a null pointer constant other than NULL is used. That
approach seems more likely to get to where you hope to get to.
Nov 15 '05 #41

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:

[...]
I've used other languages that have a keyword that's used as the
equivalent of a null pointer constant, and that don't allow any other
form of null pointer constant. I'll just mention that programmers in
those languages typically don't know or care how null pointers are
represented; even if they happen to know how a given implementation
represents null pointers, they don't try to make use of the knowledge.
And their FAQs don't have to devote an entire section to null
pointers.


Sure; certainly there are some benefits to the 'nil' approach.
I don't think there are any costs to this approach, apart from the
insurmountable cost of all the existing C code that would be broken.


In my experience these kinds of design choices essentially always
carry ongoing costs as well as benefits. That isn't to say that the
benefits won't outweigh the costs necessarily, only that there also
are costs to consider. So if you aren't aware of any costs besides
the cost of converting existing code, maybe you haven't considered
the ramifications fully enough yet?

To put this another way, when C was being designed, there already were
languages with, eg, NULL to indicate null pointers (and no other forms
allowed). Yet KT and/or DR decided to use 0 for null pointers, so
they must have thought there were some benefits to doing that over
using NULL. If the original C model has some benefits, then giving
those up is a cost.


C was based on a couple of earlier languages. BCPL, if I recall
correctly, was a low-level language that treated all of memory as an
array of words; pointers were effectively indices into that array.

Conceivably there might be some advantage (other than historical) in
C's approach rather than defining single keyword for null pointers. I
just can't think of anything. Can you?
I'm almost tempted to suggest adding a "nil" keyword to the next C
standard, with the obvious semantics, *without* eliminating the other
forms of null pointer constant. But providing a better approach
without removing the old one would just add to the confusion.


Why not just use NULL? A lint-like tool, or a compiler warning
switch, could be used to flag those cases where a pointer value is
needed yet a null pointer constant other than NULL is used. That
approach seems more likely to get to where you hope to get to.


I have no real hope of getting anywhere with 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.
Nov 15 '05 #42

P: n/a
Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes: [...]
C99 6.3.2.3p3 defines the term "null pointer constant":

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

I don't see any permission for the implementation to define null
pointer constants that don't meet that definition. 7.17p3 says that
the macro NULL "expands to an implementation-defined null pointer
constant". This allows the implementation to define NULL as either 0,
(void*)0, or ('/'/'/'-'/'/'/'); it doesn't allow it to define NULL as
(void*)(char*)0. 7.17p3 constrains the implementation's definition of
NULL; it doesn't define "null pointer constant".


I agree the issue is not clear cut. I wasn't meaning to start a
debate on the issue, only to give a plausible and reasonable
alternative reading. However, since you ask, let me frame some
arguments.


Actually, we aren't in agreement. I think the issue is (reasonably)
clear-cut.


I don't see any inconsistency between saying the issue is reasonably
clear-cut and saying the issue is not clear cut. There's a difference
in degree between the two statements, but they aren't inconsistent.

So I'm not sure that I can agree that we aren't in agreement. :)

1. The Standard isn't always careful in how definitions are given.
There was discussion recently on the definition of "definition", for
example. Although I think it would be a good idea if the Standard
were more rigorous (and, dare I say it, "mathematical") in defining
and using special terms, that isn't what it does now.


Agreed. However, there are cases where the standard gives explicit
permission to do something in an implementation-defined way, such as
the declaration of main(). The fact that it doesn't do so here is,
IMHO, significant.


Saying you believe it's significant isn't really a very convincing
argument, is it?

More specifically, look at the wording of 5.1.2.2.1, where 'main' is
specified. Clearly paragraph 1 intends to give a precise
specification of 'main'; in particular, the word "shall" is used.
The wording used in 6.3.2.3 p3 is quite different. The analogy
just doesn't seem strong enough to be very convincing.

2. Note the particular wording in 6.3.2.3 p3: such-and-such kind of
expression *is called* a null pointer constant. It doesn't say the
list is exhaustive. If there are any candidates for definitions in
the Standard that are one-way definitions rather than two-way
definitions, surely the statement in 6.3.2.3 p3 must be one of them.


Since there's a clear and unambiguous interpretation assuming the
definition is exhaustive, I believe that's the best interpretation.


If you want to believe that, it's ok with me. But your statement
doesn't offer me any reason why I should believe it.

Furthermore, there's an obvious reason not to believe it, which is
that interpreted as an exhaustive definition, the given wording is
clearly incomplete since it doesn't cover things like '((void*)0)'.

The standard doesn't give explicit permission for other forms of null
pointer constant. Using (void*)42 in a context that requires a null
pointer constant is a constraint violation. An implementation that
doesn't issue a diagnostic for such a use is non-conforming.
Saying an implementation that doesn't issue a diagnostic for such a
use must be non-conforming is predicated on the assumption that
implementation-defined null pointer constants aren't allowed. It's
circular reasoning.

On the other hand, an implementation certainly is free to choose a
representation for pointers where any address under, say, 100 is to be
interpreted as a null pointer. On such an implementation, it would be
perfectly reasonable for '(void*)42' to be allowed as a null pointer
constant.

Similarly, the standard doesn't give permission for other forms of
integer constants. An implementation can accept 0b11001001 as a
binary constant as a language extension, but it must issue a
diagnostic for any such constant in conforming mode.
Not the same thing at all. The form of integer constants is specified
by syntax rules; these rules have a precise and exact meaning. I
don't have a reference handy, but I believe there is a statement in
the Standard to the effect that a syntax violation must result in a
diagnostic. Certainly using an implementation-defined null pointer
constant *might* result in a diagnostic being issued, but I don't know
of any provision that *requires* one.

3. The mere use of the term "implementation-defined null pointer
constants" suggests that there are some null pointer constants that
are defined by the implementation rather than by the Standard.
Otherwise, 7.17 p3 could have said just that "NULL expands to a null
pointer constant". Based on the way other parts of the Standard are
written, the more concise form seems more likely if an implementation
were not allowed to define null pointer constants (perhaps with a
footnote that says, eg, "The choice of which null pointer constant
expression to use is implementation defined.").


The term "implementation-defined" doesn't just mean that the
implementation gets to make a choice; it also means it has to document
that choice. If the standard merely said that NULL expands to a null
pointer constant, an implementation wouldn't be required to document
what it actually expands to. This would be no great loss, since code
shouldn't depend on the choice, but I believe the intent is that (a)
an implementation can choose any valid null pointer constant as the
expansion of NULL, and (b) it must document what choice it makes.


That's a plausible interpretation. However, that interpretation seems
better expressed by saying, eg, "NULL expands to a null pointer
constant; the choice of which null pointer constant is implementation
defined." You haven't really given any kind of convincing reason,
merely stated that you believe that's the intent. In the absence of
any such reason, allowing NULL to define an implementation-defined
null pointer constant seems like a better fit to the existing
language, because otherwise that language would probably have been
rewritten to better express the intent you suggest.

It wouldn't make sense to use the phrase "implementation defined" only
in a footnote.


I agree that it's better to put the "implementation defined" phrase
in the main text, in either interpretation; as mentioned above.

4. If we take 6.3.2.3 p3 as precisely delimiting the set of
expressions that are null pointer constants, then, as you yourself
pointed out, '((void*)0)' would not be a null pointer constant.
Yet

int (*fp)(int);
fp = ((void*)0);

works. (At least, I'm not aware of any implementation where it
doesn't work.) This code isn't allowed to work (without a diagnostic)
unless '((void*)0)' were a null pointer constant. So what are we to
believe? That lots of implementations got it wrong, or that the set
of expressions mentioned in 6.3.2.3 p3 is not exhaustive? The second
alternative seems more likely. If the set of expressions mentioned in
6.3.2.3 p3 is not exhaustive, then of course any additional forms of
null pointer constant would be implementation defined.


I believe the glitch in 6.3.2.3p3, which implies that (void*)0 is a
null pointer constant but ((void*)0) isn't, is simply an oversight. I
suspect the authors of the standard just assumed that an expression in
parentheses is equivalent to the expression without parentheses -- and
of course enclosing macro definitions in parentheses is almost always
a good idea. Implementations actually conform to the intent of the
standard in this case, rather than to the literal wording. I wouldn't
infer anything significant from this (though I'd certainly like to see
this corrected.)


A small correction - implementations conform to what *you presume* the
intent of the standard is. If implementation-defined null pointer
constants are allowed, then they may be conforming to the actual
standard and not just to the intent.

If your suspicion about simply forgetting about enclosing parentheses
were right, then other more complicated forms of "null pointer
constants" shouldn't work. Have you tried any of these? If not
you may be surprised by what you find.

5. In the absence of any clearly compelling argument to the contrary,
the reading that puts less strain on the interpretation seems better.
Basically, Occam's Razor. Unless there is specific evidence that an
implementation is forbidden from defining particular forms of null
pointer constants, it's a better match to the observed facts to
assume that it's allowed.


I disagree. I find it much simpler to assume that the definition of
"null pointer constant" means exactly what it says, modulo the
parentheses glitch. The intent of the phrase "implementation-defined
null pointer constant" in 7.17p3 is quite clear given this
interpretation; there's no need to invent the idea of additional
implementation-defined *forms* of null pointer constant. There's also
no advantage in doing so; we have more than enough null pointer
constants already without allowing implementations to invent their
own.


If I may paraphrase, what you think is that the document authors
screwed up, because your interpretation is simpler? Or is it
the other way around?

Perhaps that was a little unfair. But I don't see any real substance
here; if one assumes your position, then everything is consistent and
clear. However that's equally true for the other position. I don't
see any reason, on those grounds, that anyone should prefer one
position over the other.
Nov 15 '05 #43

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes: [...]
> 5. In the absence of any clearly compelling argument to the contrary,
> the reading that puts less strain on the interpretation seems better.
> Basically, Occam's Razor. Unless there is specific evidence that an
> implementation is forbidden from defining particular forms of null
> pointer constants, it's a better match to the observed facts to
> assume that it's allowed.


I disagree. I find it much simpler to assume that the definition of
"null pointer constant" means exactly what it says, modulo the
parentheses glitch. The intent of the phrase "implementation-defined
null pointer constant" in 7.17p3 is quite clear given this
interpretation; there's no need to invent the idea of additional
implementation-defined *forms* of null pointer constant. There's also
no advantage in doing so; we have more than enough null pointer
constants already without allowing implementations to invent their
own.


If I may paraphrase, what you think is that the document authors
screwed up, because your interpretation is simpler? Or is it
the other way around?

Perhaps that was a little unfair. But I don't see any real substance
here; if one assumes your position, then everything is consistent and
clear. However that's equally true for the other position. I don't
see any reason, on those grounds, that anyone should prefer one
position over the other.


There's not a whole lot more to be said, but I've just posted a
question to comp.std.c. Perhaps we can get an interpretation from the
folks who actually wrote the standard.

--
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.
Nov 15 '05 #44

P: n/a
Keith Thompson <ks***@mib.org> writes:
Conceivably there might be some advantage (other than historical) in
C's approach rather than defining single keyword for null pointers. I
just can't think of anything. Can you?


I have my own opinions about what some of these are,
but perhaps we can get some other regulars to voice
their opinions on the subject. I don't want to get
involved in a debate about the relative merits of
the two approaches.
Nov 15 '05 #45

This discussion thread is closed

Replies have been disabled for this discussion.