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

A

Antoine Leca

I did redirect further discussions toward comp.std.c only.

En (e-mail address removed), Keith Thompson va escriure:
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
 
C

CBFalconer

Antoine said:
.... 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.
 
D

Douglas A. Gwyn

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

Antoine Leca

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

En (e-mail address removed), 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
 
D

Douglas A. Gwyn

pete said:
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.
 
D

Douglas A. Gwyn

Antoine said:
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.
 
K

Keith Thompson

Antoine Leca said:
[fscanf which could create null pointers if the standard is revised, while
now it can't.]

En (e-mail address removed), 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.
 
K

Keith Thompson

Douglas A. Gwyn said:
(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.
 
D

Douglas A. Gwyn

Keith said:
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.
 
B

Brian Inglis

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

Michael Wojcik

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 (e-mail address removed)

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
 
A

Antoine Leca

En (e-mail address removed), Douglas A. Gwyn va escriure:
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
 
R

Richard Kettlewell

Keith Thompson said:
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.
 
K

Keith Thompson

Douglas A. Gwyn said:
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.
 
K

Keith Thompson

Richard Kettlewell said:
Keith Thompson said:
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.
 
M

Michael Wojcik

Keith Thompson said:
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".
 
D

Douglas A. Gwyn

Keith said:
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.
 
K

Keith Thompson

Douglas A. Gwyn said:
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.
 
D

Douglas A. Gwyn

Keith said:
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
 
I

infobahn

Douglas A. Gwyn said:
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.
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.
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>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top