473,324 Members | 2,214 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,324 software developers and data experts.

printf("%p\n", (void *)0);

printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */
Nov 14 '05
188 17138
Keith Thompson wrote:
.... snip ...
It might even be nice to have a more expansive definition of validity
for this context than for others. For example, the standard *could*
specify that this:

void *ptr = malloc(1);
if (ptr != NULL) {
free(ptr);
printf("ptr = %p\n", ptr);
}

does not invoke undefined behavior. (printf doesn't have to treat the
value as a pointer; it could, for example, type-pun it as an array of
unsigned char to determine a hexadecimal representation.)


I don't think printf has a problem with this, but the calling code
may. The problems arise while accessing the value of ptr in order
to pass it.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson

Nov 14 '05 #51
CBFalconer <cb********@yahoo.com> writes:
Keith Thompson wrote:

... snip ...

It might even be nice to have a more expansive definition of validity
for this context than for others. For example, the standard *could*
specify that this:

void *ptr = malloc(1);
if (ptr != NULL) {
free(ptr);
printf("ptr = %p\n", ptr);
}

does not invoke undefined behavior. (printf doesn't have to treat the
value as a pointer; it could, for example, type-pun it as an array of
unsigned char to determine a hexadecimal representation.)


I don't think printf has a problem with this, but the calling code
may. The problems arise while accessing the value of ptr in order
to pass it.


Good point; I withdraw the suggestion.

--
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 14 '05 #52
"aegis" <ae***@mad.scientist.com> writes:
[snip]

Ok, I'm done 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 14 '05 #53

"CBFalconer" <cb********@yahoo.com> wrote in message
news:42***************@yahoo.com...
As far as the statement
(assuming a proper environment for it) is concerned, printf is
supposed to dump out a representation of a pointer value. NULL is
a suitable value for a pointer. (void *)0 is a means of generating
that NULL value. I see no reason for any implementor to
distinguish it, dereference it, or to criticize its ancestry, so I
should not expect any problems from the snippet.


I disagree.

While a pointer may be assigned to the null pointer value, it's usage by
library functions is either explicitly included or excluded. In this case,
I agree that an implementation probably will not dereference it, since the
behavior is implementation defined. However, 'probably' doesn't cut it; the
standard must clearly state the legality.

I believe this is an accidental undefined behavior, and should be clarified.

There are two reasons I believe this to be the case.
My first reason is that the behavior is, at the very least, ambiguous. The
standard does not specify the output generated from the %p conversion
specifier. It simply states that it will be "converted to a sequence of
printing characters, in an implementation-defined manner." (see 7.19.6.1).

It is important to note that the standard does not specify if the value will
be dereferenced, nor if it must conform to a range (for example, a
legitimate address inside the address space, or the null pointer).

The only constraint is that it must be a pointer to void. The pointer to
void (from 6.2.5) "shall have the same representation and alignment
requirements as a pointer to a character type." We may therefore conclude it
has a specific representation and alignment, but nothing more.

Several thread responses have asserted that the lack of a range implies that
any pointer value may be used. I tend to agree, and my testing on several
compilers shows that the tested implementations concluded this as well.

However, a gut feeling and real-world implementations do not equate to the
actual specification.

As the actual standard does not include a range requirement, we may conclude
that any properly aligned value, regardless of it being inside the program's
address space or being a null pointer, can be used as an argument. This
also tends to reinforce (but not explicitly state) that the pointer will not
be dereferenced.

So, at the outset, the behavior is ambiguous and possibly undefined, and
therefore requires elaboration.

Now, I will present how the behavior is actually undefined.

We must be very careful about the definitions. Almost all responders have
used their own beliefs about the definitions, rather than using the actual
definitions provided in the standard.

"Each of the following statements applies unless explicitly stated otherwise
in the detailed descriptions that follow: If the argument to a function has
an invalid value (...) or a type (...) not expected by a function with
variable number of arguments, the behavior is undefined." (see 7.1.4)

The definition of invalid values include values outside the domain of the
function, pointers outside the address space of the program, and a null
pointer. Therefore, it must be explicitly stated that the null pointer or a
pointer outside the address space of the program may be used, or else their
use is an undefined behavior.

While I could use that last point as proof enough for my debate, it has
already been contested by others, so I will use another method.

Continuing to 7.19.6.1, the description of the %p conversion specifier, "The
argument shall be a pointer to void. The value of the pointer is converted
to a sequence of printing characters, in an implementation-defined manner."

The actual standard requires "a pointer to void". It does not say (as many
other posters have suggested) "NULL that may be used as a suitable value for
a pointer", "the address of an object", "a pointer that is turned off", "a
pointer pointing to no particular object", "not a dog and not an airplane",
or any of the other analogs presented.

It must be a pointer to void, nothing else, by it's own definition. This is
not ambiguous.

A pointer to void (from 6.2.5) "shall have the same representation and
alignment requirements as a pointer to a character type." There is no
definition expressly allowing the type pointer to void to be compatible with
the NULL pointer constant, nor for a pointer to void to be compatible with a
null pointer.

Referring back to 7.1.4, the question is simply: "Are the null pointer and
the NULL pointer constant proper pointers to void, including the
representation and alignment requirements, and therefore valid values for
this printf conversion specifier?" If not, then it is clearly stated to be
undefined behavior.

Applying the recursive definitions given in 6.2.5, the pointer to void is:
"an object whose value provides a reference to an entity of the void type,
comprising an empty set of values; it is an incomplete type that cannot be
completed."

Continuing with 6.3.2.3, "A pointer to an object or incomplete type may be
converted to a pointer to a different object or incomplete type. If the
resulting pointer is not correctly aligned for the pointed-to type, the
behavior is undefined."

Nowhere in the standard is the null pointer required to have the same
representation and alignment requirements as a pointer to void type, only
that it is implementation defined. The NULL pointer constant is similarly
defined to expand to an implementation defined null pointer constant. (see
7.17)

Therefore, if both the implementation defined values for NULL and the null
pointer are properly aligned as a pointer to void, the results are defined.
Otherwise, this case results in undefined behavior.

Since we cannot assume that one implementation defined behavior (alignment
requirement) will match a second implementation defined behavior (value of
null pointer), when the behaviors are not required by the standard to be
simultaneously met, we must conclude that the test fails. The behavior is
therefore specified as undefined.

I see three possible corrections:

1. Limit the range to valid pointers: The value of the argument must point
to a valid object.

2. Limit the range to within the program, and include null pointers: The
value must be either a valid pointer within the address space of the
program, or a null pointer.

3. Remove the 'pointer to void' requirement: The value must be a constant
integer expression which is converted to a pointer type pursuant to the
rules of 6.3.2.3. (ie, there are no alignment requirements nor address
space requirements, and the value may be a trap representation.)

The first solution would probably break some code, including the case the OP
suggested. The second solution seems to be the intended meaning as written,
although it also breaks a small body of existing code. The third solution
appears to be how the tested implantations performed the operation, but some
implementations may require changes to meet it.

bryanw / frob
Nov 14 '05 #54
In message <11*********************@o13g2000cwo.googlegroups. com>
"Peter Nilsson" <ai***@acay.com.au> wrote:
aegis wrote:
Saying a pointer that is a null pointer, points to nowhere,
is not meaningful. And in fact, that is an oxymoron. Because
as a pointer, it will point to something. That is the nature
of a pointer. But the issue is whether or not that something
it points at, is meaningful. And yes, ... 'no object' is
a thing. It is a distinguishable entity crafted by the
committee so that one can differentiate between 'no object'
and 'object'.


So, NO OBJECT is a THING-IN-ITSELF?


[spoilers]








You obviously haven't played the superb Hitchhiker's Guide to the Galaxy text
adventure, in which "no tea" is an item of your starting inventory.

The solution to the final puzzle requires removing your common sense, picking
up some tea, at which point the game says you've dropped the no tea. Then
you pick back up the no tea, thus holding both tea and no tea simultaneously.

This paradox demonstrates your superior intelligence to one of the ship's
robotic doors, which will then open for you.

Of course, removing your common sense works well for c.l.c too, I find.

--
Kevin Bracey, Principal Software Engineer
Tematic Ltd Tel: +44 (0) 1223 503464
182-190 Newmarket Road Fax: +44 (0) 1728 727430
Cambridge, CB5 8HE, United Kingdom WWW: http://www.tematic.com/
Nov 14 '05 #55
On Sun, 06 Mar 2005 02:34:34 +0000, Keith Thompson wrote:
infobahn <in******@btinternet.com> writes:
printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */
Ooh, good catch!

Assuming it appears in a valid context (within a function, and with a
"#include <stdio.h>" in the right place), a strict reading of the
standard could lead to the conclusion that it's undefined behavior.
However, I think it's clear that it's not *intended* to be undefined
behavior, and the standard can (and IMHO should) be read so that it
isn't. (The output is implementation-defined, of course, but that's
not what your asking about.)

C99 7.1.4, "Use of library functions", says:

Each of the following statements applies unless explicitly stated
otherwise in the detailed descriptions that follow: If an argument
to a function has an invalid value (such as a value outside the
domain of the function, or a pointer outside the address space of
the program,


These two will always produce undefined behaviour before the function is
even called.
or a null pointer,
The case in question. However I read this as a list of possibilities, this
section does NOT make all null pointer arguments to standard library
functions invalid. It cannot do so because there are clarly valid cases
such as fflush(NULL). It is up to the specification of individual
functions as to whether null pointer arguments are valid.
or a pointer to non-modifiable
storage when the corresponding parameter is not const-qualified)
This could be problematic because the corresponding argument for %p is not
const qualified. However the "list of possibilities" issue is the same as
that for a null pointer argument.
or a type (after promotion) not expected by a function with
variable number of arguments, the behavior is undefined.
This just confirms the application of variable argument rules for standard
library functions.
C99 7.19.6.1p8, "The fprintf function" (page 279) says:

p The argument shall be a pointer to void. The value of the
pointer is converted to a sequence of printing characters, in
an implementation-defined manner.

Since this doesn't explicitly say that a null pointer is allowed, one
could argue that it's undefined behavior.
A null pointer is a perfectly valid pointer value. The section above makes
a clear definition of behaviour (albeit implementation-defined) for
pointer values without exception. As such there is no possibility of
undefined behaviour arising from here. I.e. if the code managed to get
this far without invoking undefined behaviour it is fine.
The escape clause, I think is that 7.1.4 says "If an argument to a
function has an invalid value (*such as* ... a null pointer ...)". If I
turn my head to one side and squint, I can read this as saying that a
null pointer can be an invalid value, not necessarily that it always is
one.
This is a reasonable interpretation, and I see no other way of
interpreting it that is compatible with the rest of the standard.
Therefore it is the correct interprtation (given that no other
"compatible" interpretations surface).
On the other hand, the same reasoning could imply that strlen(NULL)
doesn't invoke undefined behavior. We have to use common sense to
determine that printf("%p\n", (void*)0)) is ok but strlen(NULL) is not
-- but some people's "common sense" will lead them to conclude that the
latter should always return 0.
strlen(NULL) is invalid because it violates the specification of strlen(),
specifically:

"The strlen function computes the length of the string pointed to by s."

The specification of strlen() defines no behaviour if the value of s is
not a pointer to a string, i.e. you have undefined behaviour. A null
pointer is not a pointer to a string. There is nothing equivalent that
makes a null pointer invalid for %p.
Realistically, any implementation won't do anything more exotic that
printing some implementation-defined character string.

Still, I think this calls for a DR.


I see only one viable interpretation of the standard.

Lawrence

Nov 14 '05 #56
In article <11**********************@g14g2000cwa.googlegroups .com>,
ae***@mad.scientist.com says...
'no object' is a thing. It is a goddamn concept. And that concept
is used to define a value that is used with pointers so that
one may get an answer to the question,
'do I point to an object or no object?'

Please engage your brain before posting next time.


You're on crack, and doing a very weak Dan Pop impression in
the bargain.

--
Randy Howard (2reply remove FOOBAR)
"Making it hard to do stupid things often makes it hard
to do smart ones too." -- Andrew Koenig
Nov 14 '05 #57

frob wrote:
"CBFalconer" <cb********@yahoo.com> wrote in message
news:42***************@yahoo.com...
Per 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."

An null pointer constant (NPC) has a type, which can be either an
integer type, or "pointer to void", depending upon which way it
qualifies as an NPC. The purpose of NPCs is that when they appear in
certain contexts, they implicitly get converted to a null pointer of
the appropriate type. For instance, in

int i;
int *p=&i;

if(p == 0)
....
The null pointer constant on the right gets special treatment because
of the fourth item in section 6.5.9p2. If it weren't for that item,
this code would constitute a constraint violation. Because of 6.5.9p5,
the null pointer constant gets convert to 'int*', therefore qualifying
as a null pointer.

The other places where NPCs get similar special treatement are in ?:
(6.5.15p3,6) and simple assignment (6.5.16.1p1), and initializers
(6.6p7).

The argument list of a variadic function is not one of the contexts in
which null pointer constants get special treatement. However, (void*)0
qualifies not only as a null pointer constant, it's also a null pointer
in it's own right, because 0 is also an NPC, and 'void*' is a pointer
type, so (void*)0 is a null pointer of type "pointer to void".

The NULL macro is a standard defined macro whose expansion is
guaranteed to be a null pointer expression. The word NULL has no other
special meaning. In particular, your frequent reference to "NULL
pointer" below is meaningless; I believe that what you intend in those
contexts is "null pointer".

A null pointer value is a pointer value, not dereferenceable, but valid
for purposes such as comparison for equality and assignment to a
pointer object. NULL is a macro, whose expansion is a null pointer
constant such as (void*)0. A "null value" is a meaningful phrase; "NULL
value" is meaningless.
While a pointer may be assigned to the null pointer value,
ITYM that a null pointer value may be assigned to a pointer object?
any pointer value may be used. I tend to agree, and my testing on several compilers shows that the tested implementations concluded this as well.

How can you test whether code has undefined behavior? How precisely
would you distinguish a pass from a fail? The "undefined behavior"
produced by a given implementation could consist of printing out a
hexadecimal string corresponding to the bit pattern of the pointer,
interpreted as an unsigned integer of the corresponding size - in other
words, indistinguisheable from the behavior when the behavior is
defined.

Undefined behavior can be determined only by analysis, not by
experimentation.
"Each of the following statements applies unless explicitly stated otherwise in the detailed descriptions that follow: If the argument to a function has an invalid value (...) or a type (...) not expected by a function with variable number of arguments, the behavior is undefined." (see 7.1.4)

The definition of invalid values include values outside the domain of the function, pointers outside the address space of the program, and a null pointer.
That's not a definition. Definitions of terms in the standard are
identified either by the fact that the term appears as a paragraph
heading in the "Definitions" section, or by the fact that the term
being defined is printed in italic type. Neither of those applies here.
Those were merely examples of invalid values, and null pointers aren't
necessarily invalid values for all standard library functions.
... Therefore, it must be explicitly stated that the null pointer or a pointer outside the address space of the program may be used, or else their use is an undefined behavior.
If that were a definition, I would agree; since it's actually only a
list of examples, your conclusion doesn't follow.
Continuing to 7.19.6.1, the description of the %p conversion specifier, "The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner."
The actual standard requires "a pointer to void". It does not say (as many

Which (void*)0 qualifies as.
A pointer to void (from 6.2.5) "shall have the same representation and alignment requirements as a pointer to a character type." There is no definition expressly allowing the type pointer to void to be compatible with the NULL pointer constant, nor for a pointer to void to be compatible with a null pointer.
No, instead there is language indicating that an NPC shall become a
null pointer value when converted to pointer type. There are other
sections which indicate that the result of a cast operation is a value
of the specified type, which in this case happens to be 'pointer to
void'. Therefore, (void*)0 is indeed a null pointer of type 'pointer to
void'.
Referring back to 7.1.4, the question is simply: "Are the null pointer and the NULL pointer constant proper pointers to void,
There is no unique "null pointer", so your use of the phrase "the null
pointer" is inapprpriate. Each pointer type has its own null pointer
value and each pointer type may have multiple different representations
of the null pointer value. They may all have the same representation
(though that's not required); however, all null pointers are required
to compare equal, and to compare unequal to an pointer to an actual
object or function.

A null pointer value can be a pointer to void, if that's it's type. A
null pointer such as (char*)0 is obviously not of that type. A NPC of
integer type is a pointer to void only if it occurs in one of the
contexts where it gets implicitly converted to 'void*'. However, the
particular NPC (void*)0 starts out as a pointer to void, so it doesn't
need implicit conversion.
Nowhere in the standard is the null pointer required to have the same representation and alignment requirements as a pointer to void type,
Except, of course, when it has "pointer to void" type.
1. Limit the range to valid pointers: The value of the argument must point to a valid object.

2. Limit the range to within the program, and include null pointers: The value must be either a valid pointer within the address space of the
program, or a null pointer.
That's redundant; null pointer values are valid pointer values for
purposes of comparison for equality, and for assignment. They're not
valid for dereferencing or comparison for order, but they are valid for
some purpose. In the absence of further qualification, the phrase
"valid pointer" must be satisfied by null pointers. The phrases
"pointer value valid for derefencing" or "pointer value valid for all
possible uses" would not include null pointer values; but that's not
the phrase that was used.
3. Remove the 'pointer to void' requirement: The value must be a constant integer expression which is converted to a pointer type pursuant to the rules of 6.3.2.3. (ie, there are no alignment requirements nor address space requirements, and the value may be a trap representation.)


That wouldn't work; since the relevant argument is a variadic one,
printf() needs to know what type it is, in order to correctly extract
it. Since pointers to different types can be of different sizes, it
wouldn't have any way to know how many bytes to extract. Pointers to
different types can also have different representations, even if they
have the same exact size. Only by restricting the argument to a
specific pointer type is is possible for printf() to do it's job.

Nov 14 '05 #58
[Writing from comp.std.c point of view.]

En 11*************@news.supernews.com, Andrey Tarasevich va escriure:
The specification of 'printf' does not say that passing null
pointers to it is OK.
So it is UB.
That's exactly what constitutes the problem.


Where is it a problem?
Put in other words, what exactly is missing when one cannot print a value
for a null pointer?

I think it would be _much_ better to have specific code to deal with null
pointers, rather than receive random ones with fscanf(), for instance.
Antoine

Nov 14 '05 #59
aegis wrote:
Keith Thompson wrote:
"aegis" <ae***@mad.scientist.com> writes:
[...]
And yes, Keith, 'no object' is a thing.


What part of the word "no" do you not understand?

I have no dog. This "no dog" is not an object, it is not a thing, it
is not a dog. I simply don't have a dog. That's what "no" means.

A null pointer points to no object. That means that a null pointer
does not point to any object. There's no "there" there.

'no object' is a thing. It is a concept. It allows us to
answer the question
'does this pointer point to an object or no object?'


There is no need for any such thing to exist in order to do that. To see
if the address "34 Hobson Street" is a null pointer all I have to do is
look at the bit pattern. I don't have to treat it as a pointer.

You are also failing to take in to account that the space available for
C pointers to point to is finite, therefore any pointer outside that
range does not point at anything because there is nothing to point to.

It's a bit like the question "what happened before the start of time?"
If time had a definite start then such a question is meaningless because
there was no before, the same applies to C pointers. Null is a defined
value which can be written down and compared against (just as you can
compare a time value against 5 seconds before the start of time) but
null pointers still don't point at anything (or any time) because there
is no place (or time) for them to point to.

Or another analogy (no analogy being perfect) with C we are back in the
days of the flat earth where if you go too far you fall off the edge,
except with C that can be rather more true.

Another possible analogy, point at something with your finger. Then
close you fist and put your hand by your side and ask something what you
are pointing at. The most likely response is something like, "you are
not pointing at anything." However, you (the pointer) still exist, you
are just not pointing at anything.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #60
Kevin Bracey wrote:
So, NO OBJECT is a THING-IN-ITSELF?


[spoilers]


If you're going to google on "thing in itself",
then you should also google on "chair".

http://groups.google.co.uk/groups?hl...Dcomp.lang.c.*

--
pete
Nov 14 '05 #61

<ku****@wizard.net> wrote in message
news:11**********************@l41g2000cwc.googlegr oups.com...

The null pointer constant on the right gets special treatment because
of the fourth item in section 6.5.9p2. If it weren't for that item,
this code would constitute a constraint violation. Because of 6.5.9p5,
the null pointer constant gets convert to 'int*', therefore qualifying
as a null pointer.

The other places where NPCs get similar special treatement are in ?:
(6.5.15p3,6) and simple assignment (6.5.16.1p1), and initializers
(6.6p7).
In each of these (assignment, conditional, and initializers), they are
considering the NPC as an implementation defined value (7.17), not as a
pointer to an object. That special value is implementation defined, has no
alignment or representaional requirements specified, and therefore not
necessarily a pointer to void as per the requirement in 6.2.5, p26.

In other words, they have restricted range to one of an actual pointer to
void, or the null pointer.

6.3.2.3p3 specifies that the NPC is unequal to any object or function, not
that it must be a pointer to void, and 6.3.2.3p5 specifies that a pointer
type may contain data that is not correctly aligned, might not point to an
entity of the given type, and might be a trap representation. So there is
no requirement that every value which can be contained in a pointer to void
must actually be a pointer to void. Simply because an object can be
contained in a type does not mean that other values cannot be stored there
as well.

The NPC is implementation defined. It may, or may not, fit the
requiremnents of a pointer to void given in 6.2.5p26.

As a example, consider a machine requiring even alignment for a pointer to
character. Even though the object is capable of storing an odd value, it
does not make the odd value into a pointer to character. (see 6.3.2.3) The
NPC could be defined as an odd value, since this satisfies it's requirements
of not comparing equal to a pointer to any object or function given in the
same section. So in this case, the NPC does not fit the requirements for a
pointer to void.
A null pointer value is a pointer value, not dereferenceable, but valid
for purposes such as comparison for equality and assignment to a
pointer object. NULL is a macro, whose expansion is a null pointer
constant such as (void*)0.
However, it's alignment and representation is not specified. If you find
that it is, please cite the section.
Undefined behavior can be determined only by analysis, not by
experimentation.
As I imeditaly followed, "real-world implementations do not equate to the
actual specification.", as we both know.
being defined is printed in italic type. Neither of those applies here.
Those were merely examples of invalid values, and null pointers aren't
necessarily invalid values for all standard library functions.
Why not? There is no exception stated, and the standard explicitly states
the responses of the other library functions when a null pointer value is
used as a valid value. From 7.1.4, if it is an invalid value, it is
undefined behavior. In this case, it does not explictly state whether the
NPC is valid or not, which is the source of the ambiguity.
... Therefore, it must be explicitly stated that the null pointer or a
pointer outside the address space of the program may be used, or else
their
use is an undefined behavior.


If that were a definition, I would agree; since it's actually only a
list of examples, your conclusion doesn't follow.


It says "invalid value". The question is whether the not the null pointer
is invalid in this case. I argue that it is not a valid value, therefore an
undefined behavior.
The actual standard requires "a pointer to void". It does not say


Which (void*)0 qualifies as.


Please cite the section of the standard stating that the NPC is a pointer to
void.

Yes, a pointer to void can be assigned a value of the NPC, but that does not
make the NPC into a pointer to void.

No, instead there is language indicating that an NPC shall become a
null pointer value when converted to pointer type. There are other
sections which indicate that the result of a cast operation is a value
of the specified type, which in this case happens to be 'pointer to
void'. Therefore, (void*)0 is indeed a null pointer of type 'pointer to
void'.
This is demonstrably false --- the null pointer constant does not
necessarily meet the alignment and representational requirements already
mentioned. As the earlier illustrative example stated, the null pointer
could be an odd value (7.17), where the alignment of pointers to character
and pointer to void are required to have an even value (by virtue of
6.2.5p26). Both could be contained in a pointer to void, but that does not
mean that the void pointer has the alignment and representation required.

Put another way, a pointer to void may be said to contain a any of these
three:
-- A (properly aligned) pointer to void
-- An integer that has been converted to a pointer but is not a pointer to
void
-- The NPC value.
A null pointer value can be a pointer to void, if that's it's type. A
null pointer such as (char*)0 is obviously not of that type. A NPC of
integer type is a pointer to void only if it occurs in one of the
contexts where it gets implicitly converted to 'void*'. However, the
particular NPC (void*)0 starts out as a pointer to void, so it doesn't
need implicit conversion.
Again, please cite that requirement. The NPC is implementation defined, and
needn't be valid in any particular type; it only must compare unequal to a
pointer to any object or function (6.3.2.3p3).

Nowhere in the standard is the null pointer required to have the same
representation and alignment requirements as a pointer to void type,

Except, of course, when it has "pointer to void" type.


Please find a citation. Again, pointer to void has an alignment constraint,
the NPC does not.
Unless you can demonstrate that the NPC (implementation defined) is required
to be of the same alignment of a pointer to void / pointer to character
(also implementation defined), the behavior must be undefined by nature of
the definitions.

frob.
Nov 14 '05 #62
[enormous amounts of snippage]
<ku****@wizard.net> wrote in message
news:11**********************@l41g2000cwc.googleg roups.com...
... (void*)0 qualifies as [a pointer to void].

In article <d0**********@news.xmission.com> frob <br****@xmission.com> wrote:Please cite the section of the standard stating that the NPC is a pointer to
void.

Yes, a pointer to void can be assigned a value of the NPC, but that does not
make the NPC into a pointer to void.


I believe ku****@wizard.net means such things as:

extern void foo(void *);
void f(void) {
void *p = 0;
foo(p);
}

Exercise: what value is passed to function foo()? What if we write:

foo((void *)0);

instead of foo(p); does anything change?

I occasionally find myself wishing that Dennis had defined C, ages
ago, with an actual "nil" keyword or similar, and that this nil
was the only kind of "null pointer constant" that C had. The
problem of distinguishing between "null pointer constant" and "null
pointer" would virtually vanish entirely: "nil" would be *the*
null-pointer-constant, and (void *)nil, (int *)nil, (char *)nil,
and (double (*)(int))nil would be four examples of null pointers.
Moreover, it would be obvious that:

printf("%p\n", nil);

requires a compile-time diagnostic ("null pointer constant with
insufficient context to determine the required kind of null pointer
to construct"), and we would only have to argue about:

printf("%p\n", (void *)nil);

and:

void *p = nil;
printf("%p\n", p);

here.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #63
frob wrote:
<ku****@wizard.net> wrote in message
news:11**********************@l41g2000cwc.googlegr oups.com...
The null pointer constant on the right gets special treatment because
of the fourth item in section 6.5.9p2. If it weren't for that item,
this code would constitute a constraint violation. Because of 6.5.9p5,
the null pointer constant gets convert to 'int*', therefore qualifying
as a null pointer.

The other places where NPCs get similar special treatement are in ?:
(6.5.15p3,6) and simple assignment (6.5.16.1p1), and initializers
(6.6p7).

In each of these (assignment, conditional, and initializers), they are
considering the NPC as an implementation defined value (7.17), not as a
pointer to an object. That special value is implementation defined, has no
alignment or representaional requirements specified, and therefore not
necessarily a pointer to void as per the requirement in 6.2.5, p26.

In other words, they have restricted range to one of an actual pointer to
void, or the null pointer.

6.3.2.3p3 specifies that the NPC is unequal to any object or function, not
that it must be a pointer to void, and 6.3.2.3p5 specifies that a pointer
type may contain data that is not correctly aligned, might not point to an
entity of the given type, and might be a trap representation. So there is
no requirement that every value which can be contained in a pointer to void
must actually be a pointer to void. Simply because an object can be
contained in a type does not mean that other values cannot be stored there
as well.

The NPC is implementation defined. It may, or may not, fit the
requiremnents of a pointer to void given in 6.2.5p26.


Er... are you saying that a definition of NULL as (void *) 0 is not
sufficient to make NULL a constant of type void *?

As a example, consider a machine requiring even alignment for a pointer to
character.
This means that for char *p, ((char *)&p)+i, i odd, is not a valid
address for a char * -- is this really what you want to say?
Even though the object is capable of storing an odd value, it
does not make the odd value into a pointer to character. (see 6.3.2.3)
However, here, you are trying to say that sizeof char != 1 which is
clearly nonsense. A char is by definition the smallest addressable
unit which is why its size is one byte. Pointers to char obviously
must be able to hold "even" and "odd" values.
If you are talking about char **, you may be right under the above
assumption but this does nothing to prove your point.
The
NPC could be defined as an odd value, since this satisfies it's requirements
of not comparing equal to a pointer to any object or function given in the
same section. So in this case, the NPC does not fit the requirements for a
pointer to void.
As alignment and representation of void * are equal to those of char *,
this argument is nonsense.

A null pointer value is a pointer value, not dereferenceable, but valid
for purposes such as comparison for equality and assignment to a
pointer object. NULL is a macro, whose expansion is a null pointer
constant such as (void*)0.


However, it's alignment and representation is not specified. If you find
that it is, please cite the section.


???
A null pointer constant's representation is implementation defined.
(int *) 0 can have a representation differing from (void *) 0.
What is your point?
[snip]

The actual standard requires "a pointer to void". It does not say


Which (void*)0 qualifies as.


Please cite the section of the standard stating that the NPC is a pointer to
void.

Yes, a pointer to void can be assigned a value of the NPC, but that does not
make the NPC into a pointer to void.


Not "the" -- "a".
You seem to believe that there is only one null pointer constant.
(void *) 0 is in my eyes of type void * and gives me a null pointer
constant.
Maybe I am constantly missing your point.

No, instead there is language indicating that an NPC shall become a
null pointer value when converted to pointer type. There are other
sections which indicate that the result of a cast operation is a value
of the specified type, which in this case happens to be 'pointer to
void'. Therefore, (void*)0 is indeed a null pointer of type 'pointer to
void'.


This is demonstrably false --- the null pointer constant does not
necessarily meet the alignment and representational requirements already
mentioned. As the earlier illustrative example stated, the null pointer
could be an odd value (7.17), where the alignment of pointers to character
and pointer to void are required to have an even value (by virtue of
6.2.5p26). Both could be contained in a pointer to void, but that does not
mean that the void pointer has the alignment and representation required.


This example was crap and I doubt you can construct a convincing one.

Put another way, a pointer to void may be said to contain a any of these
three:
-- A (properly aligned) pointer to void
I guess your notion of alignment is off the mark.
-- An integer that has been converted to a pointer but is not a pointer to
void
Are you talking about a trap representation? Or about values which
are say out of the bounds of physical memory? Even/odd is no
possibility.
-- The NPC value.
You seem to imply that void * has to be accessed either as void * or
differently, depending on what value the representation holds.
Is this really what you mean?

A null pointer value can be a pointer to void, if that's it's type. A
null pointer such as (char*)0 is obviously not of that type. A NPC of
integer type is a pointer to void only if it occurs in one of the
contexts where it gets implicitly converted to 'void*'. However, the
particular NPC (void*)0 starts out as a pointer to void, so it doesn't
need implicit conversion.


Again, please cite that requirement. The NPC is implementation defined, and
needn't be valid in any particular type; it only must compare unequal to a
pointer to any object or function (6.3.2.3p3).


See above: The/a.
A typecast gives an explicit conversion to the specified type.

Nowhere in the standard is the null pointer required to have the same
representation and alignment requirements as a pointer to void type,


Except, of course, when it has "pointer to void" type.


Please find a citation. Again, pointer to void has an alignment constraint,
the NPC does not.


I think _you_ need some citations to prove your notion that a value
preceded by a typecast does not yield a value of the type cast to.

Unless you can demonstrate that the NPC (implementation defined) is required
to be of the same alignment of a pointer to void / pointer to character
(also implementation defined), the behavior must be undefined by nature of
the definitions.


If we use a null pointer constant given by (char *) 0 or one given by
(void *) 0 and assign it to char */void *, respectively, there is no
question about alignment.
-Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #64
frob wrote:
<ku****@wizard.net> wrote in message
news:11**********************@l41g2000cwc.googlegr oups.com...
The null pointer constant on the right gets special treatment because
of the fourth item in section 6.5.9p2. If it weren't for that item,
this code would constitute a constraint violation. Because of 6.5.9p5,
the null pointer constant gets convert to 'int*', therefore qualifying
as a null pointer.

The other places where NPCs get similar special treatement are in ?:
(6.5.15p3,6) and simple assignment (6.5.16.1p1), and initializers
(6.6p7).

In each of these (assignment, conditional, and initializers), they are
considering the NPC as an implementation defined value (7.17),


The special rules for NPC apply to any NPC, not just the one that is
implementation-defined as the expansion of the NULL macro.
... not as a
pointer to an object.
However, I do agree: none of those rules apply to a pointer to an
object; such a pointer would not qualify as an NPC.
... That special value is implementation defined, has no
alignment or representaional requirements specified, and therefore not
necessarily a pointer to void as per the requirement in 6.2.5, p26.
That implementation-defined macro (not value) is required to expand into
a null pointer constant. All null pointer constants, regardless of
whether they're the result of expanding NULL, or produced explicitly by
by user code, are required to convert into null pointers of the
specified type when converted to a pointer type. Null pointer constants
are special in that they implicitly convert into a pointer type under
circumstances where (without the special rules for NPCs) they might not
so convert.

If the explicit or implicit pointer conversion is to 'void*', as is the
case with (void*)0, then the resulting null pointer is a pointer to void.
6.3.2.3p3 specifies that the NPC is unequal to any object or function,
"compares unequal to a pointer to any object or function". When you
leave out the phrases "compares" and "a pointer to", you change the
meaning. An NPC is not only allowed, but required, to compare equal to
the value of an object, if that object has a pointer type and a null value.
... not
that it must be a pointer to void,
I never suggested that all NPCs are required to be pointers to void.
However, when an NPC is converted to a pointer type, the result is a
null pointer of that type; if the specified type is "pointer to void",
it meets the requirements of 6.2.5p26. '(void*)0' is both an NPC in it's
own right, and an NPC (0) converted to a pointer type (void*). It is
therefore both an NPC and an null pointer value. However,
... and 6.3.2.3p5 specifies that a pointer
type may contain data that is not correctly aligned, might not point to an
entity of the given type, and might be a trap representation. So there is
no requirement that every value which can be contained in a pointer to void
must actually be a pointer to void.
'pointer to void' is a type. Whether or not a value is a 'pointer to
void' depends only upon the type of the expression that created the
value; it doesn't depend upon the value itself.

An NPC is a source code construct which when converted to pointer type
results in a null pointer value of the specified type. It is not an
object; only objects can have trap representations. It is a value which
is explicitly described by the standard as being valid for use in a
comparisons for equality, in addition to several other uses. Therefore
it is, in a limited sense, a valid pointer (it is not a valid pointer
for dereferencing, for instance).
The NPC is implementation defined.
No, NPC is standard-defined - paragraph 6.3.2.3p3. The fact that "null
pointer constant" is in italics is how you can identify the fact that
this paragraph constitutes the definition of that term.
It may, or may not, fit the
requiremnents of a pointer to void given in 6.2.5p26.
Agreed - whether or not it fits those requirements depends upon whether
it contains an explicit cast to 'void*'; that cast guarantees that it is
indeed a pointer to void.
As a example, consider a machine requiring even alignment for a pointer to
character.
That's not allowed. The alignment of character types is required to be
'1'. I'll assume, for the sake of your argument, that you're actually
talking about a pointer to a type larger than char.
... Even though the object is capable of storing an odd value, it
does not make the odd value into a pointer to character. (see 6.3.2.3)
Agreed; an arbitrary pointer value is not necessarily correctly aligned
for conversion to a pointer of an arbitrary type. However, any pointer
value can be converted to a pointer to void; 'void' is not allowed to
have alignment restrictions. 'pointer to void' is allowed to have
alignment restrictions, but since we're not talking about pointer
objects, but only pointer values, the alignment restrictions of the
pointer type never come into play. Only the alignment restrictions of
the pointed-at type matter, and 'void' isn't allowed to have any.

In any event, a null pointer of any type may be freely converted to a
null pointer of any other type.

The NPC could be defined as an odd value, since this satisfies it's requirements
of not comparing equal to a pointer to any object or function given in the
same section. So in this case, the NPC does not fit the requirements for a
pointer to void.
An NPC can't be an odd value, because only arithmetic types are
meaningfully 'odd' or 'even'. An expression with arithmetic type can
qualify as an NPC only if it has a value of 0 and an integer type, and
must therefore be even.

Now, if an NPC doesn't have integral type them it must have the type
'pointer to void', and in principle it could be represented by an
address with odd alignment. However, I can't think of any way in which
portable code could detect the fact. Every operation that depends upon
the alignment of a pointer is meaningless when applied to a null pointer
value.
In practice, if an implementation gives some meaning to the alignment of
a null pointer value, I'd expect it to give it an alignment compatible
with all possible types, just like the other value return values from
malloc(); I'd be (slightly) surprised by any implementation where this
wasn't true.
A null pointer value is a pointer value, not dereferenceable, but valid
for purposes such as comparison for equality and assignment to a
pointer object. NULL is a macro, whose expansion is a null pointer
constant such as (void*)0.

However, it's alignment and representation is not specified.


Agreed; the type of NULL isn't specified. It can be any integer type, or
'void*', since NULL must expand into an NPC, and those are the only two
options for NPCs. However, the type of (void*)0 is specified by the
standard, section 6.5.4p4: "Preceding an expression by a parenthesized
type name converts the value of the expression to the named type."
being defined is printed in italic type. Neither of those applies here.
Those were merely examples of invalid values, and null pointers aren't
necessarily invalid values for all standard library functions.

Why not? There is no exception stated,


Which would be relevant if it were a definition. Since it's just a list
of examples, the absence of a exception doesn't mean that there aren't
any. Each function has it's own set of valid values, some of which are
explained explicitly, others of which are implicit. If a function is
described as dereferencing a pointer, it's implicitly required to be
dereferenceable. If it's described as comparing the pointer to another
pointer for equality, it's implicitly required to be
equality-comparable. If it's describes as being compared for order with
another pointer, the pair of pointers is required to be comparable for
order. If it's described as writing through the pointer, it's implicitly
required that the destination be writable. printf() makes no such
restrictions on the pointer that matches a "%p" format code, so none of
those implicit requirements apply.

... Therefore, it must be explicitly stated that the null pointer or a
pointer outside the address space of the program may be used, or else
their
use is an undefined behavior.


If that were a definition, I would agree; since it's actually only a
list of examples, your conclusion doesn't follow.

It says "invalid value". The question is whether the not the null pointer
is invalid in this case. I argue that it is not a valid value, therefore an
undefined behavior.


Yes, but you argue invalidly.
The actual standard requires "a pointer to void". It does not say


Which (void*)0 qualifies as.

Please cite the section of the standard stating that the NPC is a pointer to
void.


I never said that all NPCs are pointers to void. The citation for this
particular NPC is 6.5.4p4.
Yes, a pointer to void can be assigned a value of the NPC, but that does not
make the NPC into a pointer to void.
Correct. What makes it a pointer to void is the explicit cast to
'void*', not the fact that it also qualifies as an NPC.
No, instead there is language indicating that an NPC shall become a
null pointer value when converted to pointer type. There are other
sections which indicate that the result of a cast operation is a value
of the specified type, which in this case happens to be 'pointer to
void'. Therefore, (void*)0 is indeed a null pointer of type 'pointer to
void'.

This is demonstrably false --- the null pointer constant does not
necessarily meet the alignment and representational requirements already
mentioned.


You've got cause and effect reversed. You don't deduce that it's void*
because it meets those requirements; you deduce the fact that it meets
those requirements from the fact that it's required (by 6.5.4p4) to be a
void*.

.... Put another way, a pointer to void may be said to contain a any of these
three:
-- A (properly aligned) pointer to void
How can a pointer to void contain a pointer to void? That way leads to
infinite recursion. In standardese, there's a distinction between the
pointer and the address. The pointer is a C concept; the address is a
machine language concept. A C pointer typically contains a machine
address; in some implementations it contains other things as well. I
think that the standardese corresponding to what you intend to mean here
is "a valid address". However, I'm not sure what you mean. I don't know
how to even talk about the next two "options" you list, until you can
convert what you're talking about into standardese.

....
contexts where it gets implicitly converted to 'void*'. However, the
particular NPC (void*)0 starts out as a pointer to void, so it doesn't
need implicit conversion.

Again, please cite that requirement.


6.5.4p4.

The NPC is implementation defined,
Incorrect: the rules for NPCs (plural, NOT singular) are
standard-defined in 6.3.2.3p3. The particular NPC that 'NULL' expands
into is implementation-defined, but NPCs in general aren't.
... and
needn't be valid in any particular type;


Per that section, it must either be an integer expression with a value
of 0, in which case it has an integer type, or it must be such an
expression, converted to 'void*', in which case it has type 'void*'.
There's no other options allowed by that section.
Nowhere in the standard is the null pointer required to have the same
representation and alignment requirements as a pointer to void type,


Except, of course, when it has "pointer to void" type.

Please find a citation.


6.5.4p4.
Nov 14 '05 #65
"frob" <br****@xmission.com> writes:
[...]
Continuing to 7.19.6.1, the description of the %p conversion specifier, "The
argument shall be a pointer to void. The value of the pointer is converted
to a sequence of printing characters, in an implementation-defined manner."

The actual standard requires "a pointer to void". It does not say (as many
other posters have suggested) "NULL that may be used as a suitable value for
a pointer", "the address of an object", "a pointer that is turned off", "a
pointer pointing to no particular object", "not a dog and not an airplane",
or any of the other analogs presented.

It must be a pointer to void, nothing else, by it's own definition. This is
not ambiguous.
Agreed. Most of the silly analogies came up because one poster seemed
to be having trouble understanding what a null pointer is (see the
"'no object' is an object" subthread). The argument must be of type
void* (or probably a pointer-to-character, but that's irrelevant to
the current discussion).
A pointer to void (from 6.2.5) "shall have the same representation and
alignment requirements as a pointer to a character type." There is no
definition expressly allowing the type pointer to void to be compatible with
the NULL pointer constant, nor for a pointer to void to be compatible with a
null pointer.
It's very important to understand that a "null pointer constant" and a
"null pointer" are two very different things. A null pointer constant
is a construct that can appear in C source code. A null pointer is a
value (of some pointer type) that can exist in a running program.

The first half of your statement, that "[t]here is no definition
expressly allowing the type pointer to void to be compatible with the
NULL pointer constant", is basically correct. More precisely, if the
argument to printf() assocated with "%p" is a null pointer constant,
the resulting argument that's passed at run-time is not necessarily
compatible with type void*. All that means is that this:
printf("%p\n", NULL);
may invoke UB, and should be replaced with
printf("%p\n", (void*)NULL);
This is a fairly trivial point, and is not central to the current
discussion.

The second half, that there is no requirement "for a pointer to void
to be compatible with a null pointer", doesn't make much sense. There
is a null pointer value of type void*; of course that value is
compatible with type void*. As above, passing that value to printf()
may require a little extra work, such as a cast, in some cases.

The question under discussion is whether passing a null pointer value
of type void* to printf with a "%p" format invokes undefined behavior.
The subject line of this thread shows one straightforward way to do
that. All this talk about compatibility is a distraction from that
question; if someone asked about it in a separate thread, I'd refer
the poster to sections 4 and 5 of the C FAQ.

This entire discussion could have taken place nearly without reference
to passing a null pointer constant or the NULL macro to printf(). For
example:

void *null_ptr = (void*)0;
printf("%p\n", null_ptr);

null_ptr is a reference to an object of type void*, so there are no
type conversion issues. The object was initialized with a null
pointer constant of type void* (the cast is actually unnecessary), so
we know its value is a null pointer; it's declared as a void* object,
so we know its value is a null pointer of type void*. If you have
any issues with the original problem statement:

printf("%p\n", (void *)0);

that don't apply to my example above, those issues are not relevant to
this thread.

[...]
I see three possible corrections:

1. Limit the range to valid pointers: The value of the argument must point
to a valid object.
That would break existing code that uses printf's "%p" format for
pointer values that may or may not be null pointers. The "%p" format
is intended to print the value of a pointer; there's no reason for it
not to work with a null pointer value. Typical implementations
(possibly all implementations) do no extra work to support this.
2. Limit the range to within the program, and include null pointers: The
value must be either a valid pointer within the address space of the
program, or a null pointer.
I'm not sure what "within the address space of the program" means.
A program has no contiguous address space as far as the C abstact
machine is concerned.

The way I'd express it is that any value of type void* that can be
evaluated without invoking undefined behavior can be passed to
printf("%p", ...) without invoking undefined behavior.
3. Remove the 'pointer to void' requirement: The value must be a constant
integer expression which is converted to a pointer type pursuant to the
rules of 6.3.2.3. (ie, there are no alignment requirements nor address
space requirements, and the value may be a trap representation.)
Huh? You're talking about changing the type of the argument (to
what?) and requiring it to be a constant integer expression (why bring
integers into it?). With this requirement, you couldn't use
printf("%p", ...) to print the value of a pointer variable. I presume
that's not what you meant. What did you mean?

printf(), when it sees a "%p" specifier, is going to do the equivalent
of va_arg(..., void*), which means the caller has to have passed a
void* argument. printf() doesn't, and shouldn't, care how that
argument was constructed, as long as it's valid.
The first solution would probably break some code, including the case the OP
suggested. The second solution seems to be the intended meaning as written,
although it also breaks a small body of existing code. The third solution
appears to be how the tested implantations performed the operation, but some
implementations may require changes to meet it.


The second solution (as I restated it) doesn't break any code that
isn't broken already. It allows a null pointer, a pointer to an
object, or a pointer just past the end of an object. Any other
pointer value is invalid; the *caller* will invoke undefined behavior
just by evaluating it, before printf() is even called.

--
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 14 '05 #66

Randy Howard wrote:
In article <11**********************@g14g2000cwa.googlegroups .com>,
ae***@mad.scientist.com says...
'no object' is a thing. It is a goddamn concept. And that concept
is used to define a value that is used with pointers so that
one may get an answer to the question,
'do I point to an object or no object?'

Please engage your brain before posting next time.


You're on crack, and doing a very weak Dan Pop impression in
the bargain.


Did you have something intelligent you wanted to say?

--
aegis

Nov 14 '05 #67
Michael Mair <Mi**********@invalid.invalid> writes:
frob wrote:

[...]
The NPC is implementation defined. It may, or may not, fit the
requiremnents of a pointer to void given in 6.2.5p26.


Er... are you saying that a definition of NULL as (void *) 0 is not
sufficient to make NULL a constant of type void *?


A definition of NULL as (void*)0 does make NULL a constant of type void*.
A definition of NULL as 0 does not make NULL a constant of type void*.
Either definition is allowed.

Because of this,
printf("%p\n", NULL);
invokes undefined behavior (or at least ambiguously does so), because
the argument isn't necessarily of type void*; it could be of type int.

That's why nobody is talking about
printf("%p\n", NULL);
Instead, we're talking about
printf("%p\n", (void *)0);
which unambiguously passes a null pointer of type void* to printf().

The first example demonstrates a trivial error whose solution is in
the FAQ. The second demonstrates an ambiguity in the standard, which
is what we're actually discussing.

--
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 14 '05 #68
James Kuyper <ku****@saicmodis.com> writes:
frob wrote: [...] I never suggested that all NPCs are required to be pointers to
void. However, when an NPC is converted to a pointer type, the result
is a null pointer of that type; if the specified type is "pointer to
void", it meets the requirements of 6.2.5p26. '(void*)0' is both an
NPC in it's own right, and an NPC (0) converted to a pointer type
(void*). It is therefore both an NPC and an null pointer
value.


A minor quibble: (void*)0 is a source construct; a null pointer value
exists only during execution of the program. Usually we can keep
these things straight from context, but in this case the distinction
is central to this sub-discussion. (void*)0 is an NPC which results
in a null pointer value at runtime.

[...]
Put another way, a pointer to void may be said to contain a any of
these three:
-- A (properly aligned) pointer to void


How can a pointer to void contain a pointer to void? That way leads to
infinite recursion. In standardese, there's a distinction between the
pointer and the address. The pointer is a C concept; the address is a
machine language concept. A C pointer typically contains a machine
address; in some implementations it contains other things as well. I
think that the standardese corresponding to what you intend to mean
here is "a valid address". However, I'm not sure what you mean. I
don't know how to even talk about the next two "options" you list,
until you can convert what you're talking about into standardese.


Actually, I think the standard tends to use the terms "address" and
"pointer" almost interchangeably. A "pointer" can be either an object
of pointer type or a value of pointer type. An "address" is a value
of pointer type, probably the address of some object. (We had a long
discussion of this not long ago.)

frob was saying that a pointer to void may contain a pointer to void;
this actually makes sense if the first "pointer to void" refers to an
object of type void*, and the second refers to a value of type void*.

This is another of those things we usually infer from context, but in
this case the object vs. value distinction is central to the
discussion and should be stated explicitly.

--
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 14 '05 #69

Flash Gordon wrote:
aegis wrote:
Keith Thompson wrote:
"aegis" <ae***@mad.scientist.com> writes:
[...]

And yes, Keith, 'no object' is a thing.

What part of the word "no" do you not understand?

I have no dog. This "no dog" is not an object, it is not a thing, itis not a dog. I simply don't have a dog. That's what "no" means.

A null pointer points to no object. That means that a null pointer
does not point to any object. There's no "there" there.
'no object' is a thing. It is a concept. It allows us to
answer the question
'does this pointer point to an object or no object?'


There is no need for any such thing to exist in order to do that. To

see if the address "34 Hobson Street" is a null pointer all I have to do is look at the bit pattern. I don't have to treat it as a pointer.

Irrelevant. Such a thing exists for the very purpose I mentioned.
You are also failing to take in to account that the space available for C pointers to point to is finite, therefore any pointer outside that
range does not point at anything because there is nothing to point

to.

Whether there are a finite amount of resources or an infinite amount
is irrelevant. Pointing to 'no object' is a meaningful concept crafted
by the standard to distinguish between pointing at an object and no
object.
The whole point of this, is because Keith said a null pointer points
'nowhere'. And I pointed out that, that is not true. This is
because NULL is a meaningful thing that represents 'no object'.
It is an entity in an of itself. Not something that is insignificant
or does not exist.

--
aegis

Nov 14 '05 #70

Peter Nilsson wrote:
aegis wrote:
Saying a pointer that is a null pointer, points to nowhere,
is not meaningful. And in fact, that is an oxymoron. Because
as a pointer, it will point to something. That is the nature
of a pointer. But the issue is whether or not that something
it points at, is meaningful. And yes, ... 'no object' is
a thing. It is a distinguishable entity crafted by the
committee so that one can differentiate between 'no object'
and 'object'.


So, NO OBJECT is a THING-IN-ITSELF?

I see now...


Yes. :-)

--
aegis

Nov 14 '05 #71
Lawrence Kirby <lk****@netactive.co.uk> writes:
On Sun, 06 Mar 2005 02:34:34 +0000, Keith Thompson wrote:

[...]
Realistically, any implementation won't do anything more exotic that
printing some implementation-defined character string.

Still, I think this calls for a DR.


I see only one viable interpretation of the standard.


Still, it would be nice if the non-viable interpretations were
explicitly excluded rather than excluded by implication.

The standard, as it's currently written, is a bit too easy to
misinterpret as allowing only a non-null pointer for the "%p"
specifier. 7.1.4 weakly implies that null pointers are invalid; I'd
be more comfortable if that weak implication were overridden by an
explicit statement in 7.19.6.1.

(Perhaps the "such as" clause in 7.1.4p1 belongs in a footnote.)

--
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 14 '05 #72
"Antoine Leca" <ro**@localhost.invalid> writes:
[Writing from comp.std.c point of view.]

En 11*************@news.supernews.com, Andrey Tarasevich va escriure:
The specification of 'printf' does not say that passing null
pointers to it is OK.


So it is UB.
That's exactly what constitutes the problem.


Where is it a problem?
Put in other words, what exactly is missing when one cannot print a value
for a null pointer?

I think it would be _much_ better to have specific code to deal with null
pointers, rather than receive random ones with fscanf(), for instance.


I disagree. I often use "%p" to show the value of a pointer. The
displayed value typically can't be used by the program itself; it's
for my information. Much existing code presumably uses "%p" to
display pointer values that may or may not be null.

A typical implementation (possibly all implementations) already
supports printf("%p\n", (void*)0) with no extra effort; despite my
off-the-wall proposal, there's no reason for printf to do try to
dereference the pointer or do anything else other than examining it as
an integer value or as a sequence of bytes.

Even if it were decided that printf("%p\n", (void*)0) invoked
undefined behavior, implementations would continue to behave as they
do now; it would be an instance of UB that's practically never detected.

--
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 14 '05 #73
Keith Thompson <ks***@mib.org> writes:
"frob" <br****@xmission.com> writes:

[...]
2. Limit the range to within the program, and include null pointers: The
value must be either a valid pointer within the address space of the
program, or a null pointer.


I'm not sure what "within the address space of the program" means.
A program has no contiguous address space as far as the C abstact
machine is concerned.


I see now that the standard uses the phrase "a pointer outside the
address space of the program," in 7.1.4p1 as an example of an invalid
argument. I still don't think that means anything in terms of the C
abstract machine, but the ambiguity is in the standard, not in what
frob wrote.

--
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 14 '05 #74
"aegis" <ae***@mad.scientist.com> writes:
[...]
Whether there are a finite amount of resources or an infinite amount
is irrelevant. Pointing to 'no object' is a meaningful concept crafted
by the standard to distinguish between pointing at an object and no
object.
The whole point of this, is because Keith said a null pointer points
'nowhere'. And I pointed out that, that is not true. This is
because NULL is a meaningful thing that represents 'no object'.
It is an entity in an of itself. Not something that is insignificant
or does not exist.


I was going to drop this, but ...

If what a null pointer points to isn't something that does not exist,
what is? Why do we have the phrase "does not exist" in the language?

--
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 14 '05 #75
I was unclear in my previous post. I will attempt to clear it up.

When I spoke of a machine with even boundaries for char types, I was
referring to the actual executable code after the translation from C has
occurred. I was not referring to the C program source. I apologize for
being unclear on that point. I was not trying to state or imply that a
char* +1 would always be even in the C language. I was referring entirly to
the translated code for the execution environment.
The specific wording I am referring to is "same representation and alignment
requirements", given in 6.2.5.
When the standard refers to "same representation and alignment
requirements", it states in the footnote that this "implies
interchangability as arguments to functions, return values from functions,
and members of unions", I am forced to believe the wording is referring to
the implementation defined actual layout of the bits in the execution
environment, not the conceptual model in the C language source. I cannot
find any actual definition which leads me to believe otherwise.

The standard requires that the type "pointer to void" has these specific
"representation and alignment requirements", which are implementation
defined.

Also, as you and others have pointed out, NPCs may be of varied types and
are implementation defined.

Nowhere in the standard can I find that (void*)0 has or can be converted to
the "same representation and alignment requirements" as specified for the
purposes of a pointer to void. This is implied in several cases, but never
explicitly stated (to my knowledge). The 6.3.2.4p4 statement, "Conversion
of a null pointer to another pointer type yields a null pointer of that
type." This is the closest I can find, but it does not meet the exact
wording given in 6.2.6p26, respecting the "same representation and alignment
requirements."

Yes, it is a very small detail, and yes, it probably should be interpreted
as meeting those requirements. However, if we are going to be splitting
hairs over the standard, I will refer to the definition of 'implies' in
logic, which fails in this exact case.

For the library functions that explicitly state the behavior on a null
pointer, I can expect the NPCs to have a specified result, by definition.
For those functions that don't require a pointer to an object, but simply a
pointer to void, to be strictly legal I must be able to assert that the NPC
have the "same representation and alignment requirements" for the pointer to
void. (these are the three ways for the 'implies' logic to be true.) If we
cannot assert this, then the implication fails, (the fourth element of the
'implies' logic) and the behavior must be undefined.

Because I cannot find any statements requiring that the "same representation
and alignment requirements" for a pointer to void type are met in this
specific case, and since both are implementation defined, I am concluding
that the requirements could theoretically not be met.

If, somewhere in the definitions, the constraints of being the "same
representation and alignment requirements" of a pointer to void, as
specified by 6.2.5p26 are explicitly met with a statement of (void*)0, then
I agree that the behavior is well defined but poorly worded.

However, since I can find no assurance that this is true, except by
anecdotal evidence and statements of implication and infererence present
throughout the standard, I am not completely convinced that a NPC cannot be
an "invalid value" as specified in 7.1.4, since the conversion specifier
requires that the "argument shall be a pointer to void", with it's
corresponding constraints.

Yes, I am splitting hairs. Yes, it probably is not a significant thing and
we have probably wasted more time discussing it that is warranted. Yes, the
behavior is probably intended to be legal and will probably be considered
legal in the implementations. However, I have not yet been completely
assured that it is strictly legal.

frob.
Nov 14 '05 #76
Keith Thompson wrote:
Michael Mair <Mi**********@invalid.invalid> writes:
frob wrote:


[...]
The NPC is implementation defined. It may, or may not, fit the
requiremnents of a pointer to void given in 6.2.5p26.


Er... are you saying that a definition of NULL as (void *) 0 is not
sufficient to make NULL a constant of type void *?

A definition of NULL as (void*)0 does make NULL a constant of type void*.
A definition of NULL as 0 does not make NULL a constant of type void*.
Either definition is allowed.


[snip]

I am aware of that -- I just am not sure whether "frob" is aware of
the fact that there is _not_ one and only one null pointer constant.
IMO, his constant use of "the" implies the opposite.
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #77

Keith Thompson wrote:
"aegis" <ae***@mad.scientist.com> writes:
[...]
Whether there are a finite amount of resources or an infinite amount is irrelevant. Pointing to 'no object' is a meaningful concept crafted by the standard to distinguish between pointing at an object and no
object.
The whole point of this, is because Keith said a null pointer points 'nowhere'. And I pointed out that, that is not true. This is
because NULL is a meaningful thing that represents 'no object'.
It is an entity in an of itself. Not something that is insignificant or does not exist.


I was going to drop this, but ...

If what a null pointer points to isn't something that does not exist,
what is? Why do we have the phrase "does not exist" in the language?


Is the phrase in the language 'does not exist' pertinent to
what a null pointer points to?
--
aegis

Nov 14 '05 #78
frob wrote:
I was unclear in my previous post. I will attempt to clear it up.

When I spoke of a machine with even boundaries for char types, I was
referring to the actual executable code after the translation from C has
occurred. I was not referring to the C program source. I apologize for
being unclear on that point. I was not trying to state or imply that a
char* +1 would always be even in the C language. I was referring entirly to
the translated code for the execution environment.
That sounds reasonable in itself. However, the above comments (assuming
that you and I are both understanding them the same way) render your
previous argument about an NPC being 'odd' meaningless.

On a machine where addresses are required to point to word boundaries,
with words being two bytes long (a not uncommon architecture) then a
char* pointer will have to be represented by the combination of a
machine address plus some mechanism for determining which byte of the
word the character is in. On some platforms, a high-order bit within the
machine address is used by the C implementation for this purpose; this
requires that the chosen bit is not used by the machine itself. When
that approach is not feasible, it generally means that if a type T is
word aligned, then sizeof(char*) > sizeof(T*). A pointer to void is
required to have the same representation as 'char *', and will therefore
be just as easily capable of representing "odd" addresses as a 'char*'
pointer itself.

.... Nowhere in the standard can I find that (void*)0 has or can be converted to
the "same representation and alignment requirements" as specified for the
purposes of a pointer to void. This is implied in several cases, but never
explicitly stated (to my knowledge). The 6.3.2.4p4 statement, "Conversion
of a null pointer to another pointer type yields a null pointer of that
type." This is the closest I can find, but it does not meet the exact
wording given in 6.2.6p26, respecting the "same representation and alignment
requirements."
Keep in mind that objects contain represent ions of values; the value
'1' doesn't have to have a specific representation as far as C is
concerned, until it's actually stored in an object. In actual practice,
there are real machines where registers use different representations
than RAM for certain types, in which case loading the value from RAM
into a register requires a change of representation.

When it's permitted for a type to have multiple representations for a
given value (as is the case for null pointer values), there's no
guarantee that storing the same value in different objects, or in the
same object at different times, will result in the same representation
being created. Therefore, it's meaningless to ask what "the"
representation of (void*)0 is. However, an implementation is required to
create a valid representation in any 'void*' object that (void*)0 is
stored in.

You're not supposed to conclude that it qualifies as a pointer to void
because it meets those representation and alignment requirements when
stored in an object; it hasn't been stored in an object yet (and
depending upon context, it might never be), so there's no way to tell.
What you can infer is that it will meet those requirements if it gets
stored in an object because it's required (as a result of the 'void*'
cast) to be a null pointer value of type pointer to void. Since the
conversion is guaranteed to succeed, and the result of that conversion
is guaranteed to be usable in various contexts, it must also be
considered valid, at least in a limited sense. Therefore, when it gets
stored in an object the implementation is required to select a valid
representation for the value, one that matches one of the valid
representations for a 'char*' pointer with the same value (i.e., a null
pointer value).
Yes, it is a very small detail, and yes, it probably should be interpreted
as meeting those requirements. However, if we are going to be splitting
hairs over the standard, I will refer to the definition of 'implies' in
logic, which fails in this exact case.


This isn't splitting hairs; it's trying to perform the inference exactly
backwards, which is doomed to failure. (void*)0 has type 'pointer to
void' for precisely the same reason that (long)3 has type 'long int'. If
you try to find the part of the standard which describes the
representation of (long)3, to determine whether or not it meets the
requirements of 6.2.6.2, you'll have just as much trouble as you had
looking for text describing the representation and alignment of
(void*)0, and for precisely the same reasons.

It's up to the implementation to ensure that the representation for
(void*)0 meets the requirements of 6.2.5p26 for pointers to void when it
gets stored in a void* object. That's for the same reasons that it's the
responsibility of the implementation to ensure that (long)3 meets the
requirements of section 6.2.6.2 for the representation of integer types
when it gets stored in a 'long' object.
Nov 14 '05 #79
I did redirect further discussions toward comp.std.c only.

En ln************@nuthaus.mib.org, Keith Thompson va escriure:
I think it would be _much_ better to have specific code to deal
with null pointers, rather than receive random ones with fscanf(),
for instance.
I disagree. I often use "%p" to show the value of a pointer. The
displayed value typically can't be used by the program itself; it's
for my information. Much existing code presumably uses "%p" to
display pointer values that may or may not be null.


You missed my point.

I was pointing out that specifying a behaviour for fprintf("%p", (void*)0)
would be useless if (because of the symmetry) you did not specify that
fscanf("%p", &p) could make a null pointer to be stored in p.
And I guess while a number of /implementations/ are in fact ready to digest
the first form (as you pointed out), there is also a number of /programs/
that might *not* like receiving a null pointer.

And as you know, programs have priority over implementations.

A typical implementation (possibly all implementations) already
supports printf("%p\n", (void*)0) with no extra effort;
Sure. I often see them printing "(null)".
However, I am not happy about something like that being incorporated into
the C standard (particularly on 16-bit implementations where "(null)" can
change the alignments of the outputs).

Even if it were decided that printf("%p\n", (void*)0) invoked
undefined behavior, implementations would continue to behave as they
do now; it would be an instance of UB that's practically never
detected.


Of course. There are a number of them, probably the majority in fact
(particularly with *printf(), such as the relationship between signed and
unsigned).
Antoine

Nov 14 '05 #80
Antoine Leca wrote:
.... snip ...
I was pointing out that specifying a behaviour for fprintf("%p",
(void*)0) would be useless if (because of the symmetry) you did
not specify that fscanf("%p", &p) could make a null pointer to be
stored in p. And I guess while a number of /implementations/ are
in fact ready to digest the first form (as you pointed out),
there is also a number of /programs/ that might *not* like
receiving a null pointer. From N869. I see nothing to prevent bandying NULL about.


p Matches an implementation-defined set of sequences,
which should be the same as the set of sequences
that may be produced by the %p conversion of the
fprintf function. The corresponding argument shall
be a pointer to a pointer to void. The input item
is converted to a pointer value in an
implementation-defined manner. If the input item is
a value converted earlier during the same program
execution, the pointer that results shall compare
equal to that value; otherwise the behavior of the
%p conversion is undefined.

Color me dense, but I see no real use for the facility.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson

Nov 14 '05 #81
[fscanf which could create null pointers if the standard is revised, while
now it can't.]

En 42***************@yahoo.com, CBFalconer va escriure:
I see nothing to prevent bandying NULL about.

If the input item is
a value converted earlier during the same program
execution, the pointer that results shall compare
equal to that value; otherwise the behavior of the
%p conversion is undefined.
Since previous use of printf cannot convert a null pointer, you presently
fear no risk to actually receive an input item that could be converted into
a null pointer, since such a thing (that input item) is not reputed to exist
at all.

Now if the text for printf is updated, _automatically_ (no change of words)
fscanf can now store null pointers for the %p conversions. Which might upset
people which are writing e.g. portable libraries, because that now mean they
should check for these new null pointers, causing code bloat.

I see no real use for the facility.


Which one? The %p conversion? fscanf? ;-)
Antoine

Nov 14 '05 #82
aegis wrote:
p The argument shall be a pointer to void. The value of the
pointer is converted to a sequence of printing characters, in
an implementation-defined manner.


(void*)0 is a valid value of the type "pointer to void".
Thus printf is required to accept it in this context.
Nov 14 '05 #83
pete wrote:
How about printing the value of the one past pointer,
do you think that is undefined?
printf("&a + 1 is %p.\n", (void *)(&a + 1));


There's another case of a valid value for a pointer of
the type "pointer to void". Thus printf is required to
accept it and do the right thing.
Nov 14 '05 #84
Antoine Leca wrote:
If the input item is
a value converted earlier during the same program
execution, the pointer that results shall compare
equal to that value; otherwise the behavior of the
%p conversion is undefined. Since previous use of printf cannot convert a null pointer, you presently
fear no risk to actually receive an input item that could be converted into
a null pointer, since such a thing (that input item) is not reputed to exist
at all.


No, that's all wrong. Not only can fprintf convert a null
pointer value of type void* using the %p format specifier,
but there is also no problem in fscanf converting that
text sequence back to a null pointer value, which of course
will compare equal to the original value.
Now if the text for printf is updated, _automatically_ (no change of words)
fscanf can now store null pointers for the %p conversions. Which might upset
people which are writing e.g. portable libraries, because that now mean they
should check for these new null pointers, causing code bloat.


? Of course pointers need to be used properly. This is a
non-problem.
Nov 14 '05 #85
"Antoine Leca" <ro**@localhost.invalid> writes:
[fscanf which could create null pointers if the standard is revised, while
now it can't.]

En 42***************@yahoo.com, CBFalconer va escriure:
I see nothing to prevent bandying NULL about.

If the input item is
a value converted earlier during the same program
execution, the pointer that results shall compare
equal to that value; otherwise the behavior of the
%p conversion is undefined.


Since previous use of printf cannot convert a null pointer, you presently
fear no risk to actually receive an input item that could be converted into
a null pointer, since such a thing (that input item) is not reputed to exist
at all.


Are you assuming that printf("%p\n", (void*)0) invokes undefined
behavior? Since that's the point under dispute here, you might want
to make that assumption explicit.

--
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 14 '05 #86
"Douglas A. Gwyn" <DA****@null.net> writes:
aegis wrote:
> p The argument shall be a pointer to void. The value of the
> pointer is converted to a sequence of printing characters, in
> an implementation-defined manner.


(void*)0 is a valid value of the type "pointer to void".
Thus printf is required to accept it in this context.


But part of the standard can be read to imply that (void*)0 is not a
valid value of type "pointer to void".

7.1.4p1 says:

Each of the following statements applies unless explicitly stated
otherwise in the detailed descriptions that follow: If an argument
to a function has an invalid value (such as [...], or a null
pointer, [...]) or [...], the behavior is undefined.

This doesn't *quite* state that a null pointer is invalid unless
explicitly stated otherwise, but it's easy to interpret it that way.

The description of free() explicitly states that a null pointer is
allowed. The description of strlen() doesn't say anything about null
pointers, but we can infer from the above *and* from the description
of the argument ("the string pointed to by s") that a call invokes
undefined behavior if s doesn't point to a string.

On the other hand, the description of the 'p' specifier doesn't say
anything about null pointers. Since 7.1.4p1 weakly implies that null
pointers are invalid, it's too easy to infer that
printf("%p\n", (void*)0) invokes undefined behavior.

Common sense tells me that it *shouldn't* invoke undefined behavior,
but rather it should produce some implementation-defined textual
representation of a null pointer value, and I'm certain that that was
the intent. More specifically, I believe that any pointer value that
can be evaluated without invoking undefined behavior should not invoke
undefined behavior when passed to printf("%p", ...).

But I'm not comfortable depending on "common sense" to determine what
the standard means.

I can imagine a stubborn implementer creating a version of printf()
that depends on the pointer value being non-null (perhaps it shows it
as a base address and offset, or perhaps it attempts to show a few
bytes of what it points to). If I filed a bug report, I'm not sure
what chapter and verse I could cite to convince the implementer that
this is a bug. This probably isn't a realistic situation (I doubt
that any actual printf() implementation blows up on null pointers),
but it's still the kind of thing the standard should address.

--
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 14 '05 #87
On Tue, 08 Mar 2005 20:18:22 GMT in comp.std.c, Keith Thompson
<ks***@mib.org> wrote:
"Douglas A. Gwyn" <DA****@null.net> writes:
aegis wrote:
> p The argument shall be a pointer to void. The value of the
> pointer is converted to a sequence of printing characters, in
> an implementation-defined manner.


(void*)0 is a valid value of the type "pointer to void".
Thus printf is required to accept it in this context.


But part of the standard can be read to imply that (void*)0 is not a
valid value of type "pointer to void".

But I'm not comfortable depending on "common sense" to determine what
the standard means.

I can imagine a stubborn implementer creating a version of printf()
that depends on the pointer value being non-null (perhaps it shows it
as a base address and offset, or perhaps it attempts to show a few
bytes of what it points to). If I filed a bug report, I'm not sure
what chapter and verse I could cite to convince the implementer that
this is a bug. This probably isn't a realistic situation (I doubt
that any actual printf() implementation blows up on null pointers),
but it's still the kind of thing the standard should address.


Isn't undefined behaviour any behaviour not explicitly defined in the
standard for the abstract machine or the library implementation?
So is the above (undefined) case not then undefined behaviour, as is
the case with strlen()?
The behaviour of printf() with format specifier "%p" is implementation
defined, but ISTM that leaves it open to each implementation whether
they define that part of the implementation to work will null
pointers.
If it could be undefined behaviour, we have no option but to treat it
as undefined behaviour in portable code.

--
Thanks. Take care, Brian Inglis Calgary, Alberta, Canada

Br**********@CSi.com (Brian[dot]Inglis{at}SystematicSW[dot]ab[dot]ca)
fake address use address above to reply
Nov 14 '05 #88
Keith Thompson wrote:
But part of the standard can be read to imply that (void*)0 is not a
valid value of type "pointer to void".
7.1.4p1 says:
That's a misreading. The parenthetical phrase "(such as ...)"
is intended to clarify what is meant by "an invalid value",
not to completely characterize the set of invalid values.
In many function-call contexts a null pointer argument would
indeed be invalid, e.g. when a pointer to an array is specified,
but not in the case of printf("%p",vp), where any well-defined
value is permitted. (A null pointer has a "valid" value.)
On the other hand, the description of the 'p' specifier doesn't say
anything about null pointers.


It doesn't have to. A null pointer value with type "pointer to
void" is just one case covered by the fprintf spec, and in this
context it does not have any special properties.
Nov 14 '05 #89

In article <ln************@nuthaus.mib.org>, Keith Thompson <ks***@mib.org> writes:
"Peter Nilsson" <ai***@acay.com.au> writes:
[...]
Consider a cpu with 24-bit address space, but 32-bit address/data
registers. Such a machine may have 255 or more null pointer
representations, none of which point to a genuine addressable
memory location.


Actually it could have 4278190080 such pointer representations
(2**32 - 2**24). (Whether they all be treated as C null pointers is
another question.)


For a real-world example, let me invoke once again the mighty AS/400:
for its (conforming C90) implementations, the null pointer is
all-bits-zero, but all valid non-null pointer values have bit 127
set. Thus the '400 has 2**127 invalid pointer representations, but
only one is a null pointer.

(To approach the ostensible topic of this thread a bit, awhile back I
posted the output of %p formatting for some AS/400 pointers, I
believe. They're ... distinctive.)

--
Michael Wojcik mi************@microfocus.com

She felt increasingly (vision or nightmare?) that, though people are
important, the relations between them are not, and that in particular
too much fuss has been made over marriage; centuries of carnal
embracement, yet man is no nearer to understanding man. -- E M Forster
Nov 14 '05 #90
En 42***************@null.net, Douglas A. Gwyn va escriure:
Since previous use of printf cannot convert a null pointer,
<snip my bullshits, with red face>
No, that's all wrong.
Sorry.
Yes it was wrong. I was wrongly assuming %p cannot convert null pointers,
based on the feedback of the thread and a misguided reading of the text.
So the conclusions I made were completely off-tracked.

Please do not rely on my posts in this thread. Thanks.

Not only can fprintf convert a null
pointer value of type void* using the %p format specifier,
Yep.
but there is also no problem in fscanf converting that
text sequence back to a null pointer value, [...]


Disagree about your logical reasonning here.

If one assumes (as I did, and as the way you build the sentence will lead
to) that fprintf("%p" _cannot_ convert null pointers, "that text sequence"
above does not exist any more.
So yes there would be a problem.

Of course here this is an absurd reasonning.
Thanks Doug to take the time to point out my mistake.
Antoine

Nov 14 '05 #91
"Douglas A. Gwyn" <DA****@null.net> writes:
Keith Thompson wrote:

[...]
On the other hand, the description of the 'p' specifier doesn't say
anything about null pointers.


It doesn't have to. A null pointer value with type "pointer to
void" is just one case covered by the fprintf spec, and in this
context it does not have any special properties.


If that were true, we wouldn't be having this conversation. It's not
enough for the standard to be clear to people who already know the
intent.

--
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 14 '05 #92
Richard Kettlewell <rj*@greenend.org.uk> writes:
Keith Thompson <ks***@mib.org> writes:
7.1.4p1 says:

Each of the following statements applies unless explicitly stated
otherwise in the detailed descriptions that follow: If an argument
to a function has an invalid value (such as [...], or a null
pointer, [...]) or [...], the behavior is undefined.

This doesn't *quite* state that a null pointer is invalid unless
explicitly stated otherwise, but it's easy to interpret it that way.


You have to not know what "such as" means to interpret it that way.


Not really. Hypothetically, a section of the standard could refer to
"a scalar type, such as int or float". This would not imply that int
and float are the only scalar types, but it would imply that int and
float are always scalar types.

Also, the "such as" clause includes 4 examples:

a value outside the domain of the function

a pointer outside the address space of the program

a null pointer

a pointer to non-modifiable storage when the corresponding
parameter is not const-qualified)

Three of these are always invalid.

This is easy to resolve if you know the intent, but it should be
possible to infer the intent from the wording, not just vice versa.

--
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 14 '05 #93

In article <ww*************@rjk.greenend.org.uk>, Richard Kettlewell <rj*@greenend.org.uk> writes:
Keith Thompson <ks***@mib.org> writes:
7.1.4p1 says:

Each of the following statements applies unless explicitly stated
otherwise in the detailed descriptions that follow: If an argument
to a function has an invalid value (such as [...], or a null
pointer, [...]) or [...], the behavior is undefined.

This doesn't *quite* state that a null pointer is invalid unless
explicitly stated otherwise, but it's easy to interpret it that way.


You have to not know what "such as" means to interpret it that way.


Nonsense. "such as" is an English phrase; nowhere does the Standard
define it. The usage Keith suggests is common in some English
dialects, and even if it were not, the lack of a universally- (or
even generally-) recognized authority on English usage vacates claims
about what common English words and phrases "must mean".

--
Michael Wojcik mi************@microfocus.com

Even 300 years later, you should plan it in detail, when it comes to your
summer vacation. -- Pizzicato Five
Nov 14 '05 #94
Keith Thompson wrote:
"Douglas A. Gwyn" <DA****@null.net> writes:
Keith Thompson wrote:
On the other hand, the description of the 'p' specifier doesn't say
anything about null pointers.

It doesn't have to. A null pointer value with type "pointer to
void" is just one case covered by the fprintf spec, and in this
context it does not have any special properties.

If that were true, we wouldn't be having this conversation. It's not
enough for the standard to be clear to people who already know the
intent.


The wording for the %p spec was carefully chosen so that
null pointer values were included. It took a rather wild
extrapolation of an example in a general clause to even
*think* that there could be a problem. While it is
certainly possible, especially with an overactive
imagination, to misread the standard in many ways, it is
also possible to understand the intent in most cases by
considering the way in which things are worded and the
reasonability of alternative interpretations, guided in
many cases by the Rationale document. The parenthetical
phrase in C99 7.1.4p1 is, in accordance with the usual
practice, explanatory, not a definition, as is quite
clear from its introductory "such as". The requirement
boils down to "if a function argument has an invalid
value, the behavior is undefined", which needs some
explanation about what is meant by "an invalid value",
so examples are provided. Not all those examples apply
to every function.
Nov 14 '05 #95
"Douglas A. Gwyn" <DA****@null.net> writes:
Keith Thompson wrote:
"Douglas A. Gwyn" <DA****@null.net> writes:
> Keith Thompson wrote:
>> On the other hand, the description of the 'p' specifier doesn't say
>> anything about null pointers.
> It doesn't have to. A null pointer value with type "pointer to
> void" is just one case covered by the fprintf spec, and in this
> context it does not have any special properties. If that were true, we wouldn't be having this conversation. It's not
enough for the standard to be clear to people who already know the
intent.


The wording for the %p spec was carefully chosen so that
null pointer values were included.


Only implicitly. The wording is:

The argument shall be a pointer to void. The value of the pointer
is converted to a sequence of printing characters, in an
implementation-defined manner.
It took a rather wild
extrapolation of an example in a general clause to even
*think* that there could be a problem. While it is
certainly possible, especially with an overactive
imagination, to misread the standard in many ways, it is
also possible to understand the intent in most cases by
considering the way in which things are worded and the
reasonability of alternative interpretations, guided in
many cases by the Rationale document. The parenthetical
phrase in C99 7.1.4p1 is, in accordance with the usual
practice, explanatory, not a definition, as is quite
clear from its introductory "such as". The requirement
boils down to "if a function argument has an invalid
value, the behavior is undefined", which needs some
explanation about what is meant by "an invalid value",
so examples are provided. Not all those examples apply
to every function.


It is not, in my opinion, a "wild extrapolation" of 7.1.4 to assume
that it could mean that any of "a value outside the domain of the
function, or a pointer outside the address space of the program, or a
null pointer, or a pointer to non-modifiable storage when the
corresponding parameter is not const-qualified" is an invalid value.
The "such as" implies that the list is not exhaustive, i.e., that some
things not on the list are also invalid values. It does not imply
that items on the list may not necessarily be invalid -- and in fact
three of the four *are* always invalid. There's no wording
distinguishing a null pointer (which may or may not be invalid) from
the other three cases.

In fact, as far as I can tell, a call to one of the *printf() function
with a "%p" format is the *only* case where a null pointer is a valid
argument to a standard function without an explicit statement that
it's valid (as there is for free()).

For integer types, for examle, validity is straightforward; anything
other than a trap representation is valid. Pointer validity is a
tricky concept that depends on the context. For dereferencing, only
pointers to objects are valid. For arithmetic and relational
operators, a pointer to an object or just past the end of an object is
valid. For assignment and equality comparison, null pointers become
valid. It would be worthwhile to state explicitly that a null pointer
is valid in the context of the "%p" specifier. It's obviously valid
if and only if you already know that it's valid.

--
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 14 '05 #96
Keith Thompson wrote:
It is not, in my opinion, a "wild extrapolation" of 7.1.4 to assume
that it could mean that any of "a value outside the domain of the
function, or a pointer outside the address space of the program, or a
null pointer, or a pointer to non-modifiable storage when the
corresponding parameter is not const-qualified" is an invalid value.
Sure it is, since for many of the functions a null pointer
value has its own explicit semantics. With your reading,
those would all be invalid values, resulting in undefined
behavior, in which case it makes no sense for the behavior
to be specified. Thus, that is not a sensible reading.
For integer types, for examle, validity is straightforward; anything
other than a trap representation is valid
No, that is not so. The validity of a function argument
generally depends on more than its type. For example,
strcpy of more data than there is room for is clearly an
instance of an invalid integer argument.
It would be worthwhile to state explicitly that a null pointer
is valid in the context of the "%p" specifier. It's obviously valid
if and only if you already know that it's valid.


Any void-pointer *value* that is valid up to that context
is clearly meant to be handled by the %p specifier. A
null pointer value, correctly obtained, is but one of
many valid void-pointer values. Why should more be said
about any of them in this context?

Remember, this is C, not some language where "nil" has an
out-of-band representation. Null pointer values have
properties pretty much like any other pointer values,
and in fact can be implemented along the lines of
extern unsigned char __kludge; // reserved
(void*)0 == (void*)&__kludge
Nov 14 '05 #97
Keith Thompson wrote:
"Douglas A. Gwyn" <DA****@null.net> writes:
Keith Thompson wrote:
"Douglas A. Gwyn" <DA****@null.net> writes:

Keith Thompson wrote:

>On the other hand, the description of the 'p' specifier doesn't say
>anything about null pointers.

It doesn't have to. A null pointer value with type "pointer to
void" is just one case covered by the fprintf spec, and in this
context it does not have any special properties.

If that were true, we wouldn't be having this conversation. It's not
enough for the standard to be clear to people who already know the
intent.


The wording for the %p spec was carefully chosen so that
null pointer values were included.

Only implicitly. The wording is:

The argument shall be a pointer to void. The value of the pointer
is converted to a sequence of printing characters, in an
implementation-defined manner.

It took a rather wild
extrapolation of an example in a general clause to even
*think* that there could be a problem. While it is
certainly possible, especially with an overactive
imagination, to misread the standard in many ways, it is
also possible to understand the intent in most cases by
considering the way in which things are worded and the
reasonability of alternative interpretations, guided in
many cases by the Rationale document. The parenthetical
phrase in C99 7.1.4p1 is, in accordance with the usual
practice, explanatory, not a definition, as is quite
clear from its introductory "such as". The requirement
boils down to "if a function argument has an invalid
value, the behavior is undefined", which needs some
explanation about what is meant by "an invalid value",
so examples are provided. Not all those examples apply
to every function.

It is not, in my opinion, a "wild extrapolation" of 7.1.4 to assume
that it could mean that any of "a value outside the domain of the
function, or a pointer outside the address space of the program, or a
null pointer, or a pointer to non-modifiable storage when the
corresponding parameter is not const-qualified" is an invalid value.


Sure it is. "Valid values" of pointer include addresses of objects and
the value NULL. Invalid values include addresses that may once have
been valid but are no longer (such as free()'d heap entries), arbitrary
integer values and other kinds of garbage.

I would worry more about printing a stale pointer value than about a
NULL value. Are there library routines that it is safe to pass a stale
pointer to? Hardly. Are there library routines that it is safe to pass
a NULL pointer to? Of course.

printf() is by very strong implication one of the patter and might even
be the only instance of the former.

/tj3
Nov 14 '05 #98
"Douglas A. Gwyn" wrote:

Keith Thompson wrote:
It is not, in my opinion, a "wild extrapolation" of 7.1.4 to assume
that it could mean that any of "a value outside the domain of the
function, or a pointer outside the address space of the program, or a
null pointer, or a pointer to non-modifiable storage when the
corresponding parameter is not const-qualified" is an invalid value.
Sure it is, since for many of the functions a null pointer
value has its own explicit semantics. With your reading,
those would all be invalid values, resulting in undefined
behavior, in which case it makes no sense for the behavior
to be specified. Thus, that is not a sensible reading.


But Keith Thompson has already agreed that, in cases where a
null pointer value has *explicit* semantics (fflush, strtok,
etc), it's clearly valid and there's no problem. In the
case of fprintf, however, the null pointer value is *not* given
explicit semantics. If you, as a member of the ISO committee,
say it's valid, then I, as the OP for this thread, believe you,
and indeed it's the answer for which I had hoped. But I don't
agree that the answer is obvious from the Standard. Had it
been, I wouldn't have asked the question in the first place.
For integer types, for examle, validity is straightforward; anything
other than a trap representation is valid


No, that is not so. The validity of a function argument
generally depends on more than its type. For example,
strcpy of more data than there is room for is clearly an
instance of an invalid integer argument.


I think you mean strncpy here, but yes, it's a fair point.
It would be worthwhile to state explicitly that a null pointer
is valid in the context of the "%p" specifier. It's obviously valid
if and only if you already know that it's valid.


Any void-pointer *value* that is valid up to that context
is clearly meant to be handled by the %p specifier. A
null pointer value, correctly obtained, is but one of
many valid void-pointer values. Why should more be said
about any of them in this context?


It's clear to you, perhaps, but not to some other people, not
all of whom are as dense as I am when it comes to reading the
Standard. Now that we know, we know; but it is not the Standard
that informed us. And it should have been.

<snip>
Nov 14 '05 #99
"Trevor L. Jackson, III" <tl**@comcast.net> wrote in message
news:la********************@comcast.com...
I would worry more about printing a stale pointer value than about a
NULL value. Are there library routines that it is safe to pass a stale
pointer to? Hardly. Are there library routines that it is safe to pass
a NULL pointer to? Of course.

printf() is by very strong implication one of the patter and might even
be the only instance of the former.


For the former, wouldn't passing an invalid pointer to printf() invoke the
same UB that assigning it to another variable does?

For example, if this invokes UB:

void *a, *b;
a = malloc(1);
free(a);
b = a;

Then shouldn't this as well:

void *a;
a = malloc(1);
free(a);
printf("%p\n", a);

I can't conceive of how a system that legally craters on the former
(AS/400?) could work with the latter.

S

--
Stephen Sprunk "Stupid people surround themselves with smart
CCIE #3723 people. Smart people surround themselves with
K5SSS smart people who disagree with them." --Aaron Sorkin

Nov 14 '05 #100

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

192
by: Kwan Ting | last post by:
The_Sage, I see you've gotten yourself a twin asking for program in comp.lang.c++ . http://groups.google.co.uk/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&th=45cd1b289c71c33c&rnum=1 If you the oh so mighty...
6
by: dam_fool_2003 | last post by:
Hai, I thank those who helped me to create a single linked list with int type. Now I wanted to try out for a void* type. Below is the code: #include<stdlib.h> #include<stdio.h>...
15
by: Stig Brautaset | last post by:
Hi group, I'm playing with a little generic linked list/stack library, and have a little problem with the interface of the pop() function. If I used a struct like this it would be simple: ...
3
by: Jason luo | last post by:
Hi all, In c99-standard page 52,there is a sentence about void,as below: If an expression of any other type is evaluated as a void expression, its value or designator is discarded. I don't...
7
by: sunglo | last post by:
My doubt comes from trying to understand how thread return values work (I know, it's off topic here), and I'm wondering about the meaning of the "void **" parameter that pthread_join expects (I...
9
by: Juggernaut | last post by:
I am trying to create a p_thread pthread_create(&threads, &attr, Teste, (void *)var); where var is a char variable. But this doesnt't work, I get this message: test.c:58: warning: cast to pointer...
5
by: Stijn van Dongen | last post by:
A question about void*. I have a hash library where the hash create function accepts functions unsigned (*hash)(const void *a) int (*cmp) (const void *a, const void *b) The insert function...
56
by: maadhuu | last post by:
hello, this is a piece of code ,which is giving an error. #include<stdio.h> int main() { int a =10; void *p = &a; printf("%d ", *p ); //error....why should it //be an error ?can't the...
27
by: Erik de Castro Lopo | last post by:
Hi all, The GNU C compiler allows a void pointer to be incremented and the behaviour is equivalent to incrementing a char pointer. Is this legal C99 or is this a GNU C extention? Thanks in...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.