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

G

G Fernandes

infobahn said:
printf("%p\n", (void *)0); /* UB, or not? Please explain your answer.
*/

I don't think there is anything in the standard that makes this UB.
You are not dereferencing a NULL pointer (which is UB) and it's the
value of the poitner (address) that is used here.
 
W

Walter Roberson

:printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */

Depends what you mean by "UB". All that the standard mandates about
%p is that the implimentation will print -something- out, and that
if scanf("%p") is used to read it back in within the same execution
session then the result will compare equal to the original pointer.
-What- is printed is undefined -- it need not even be numeric.
It could print out verses from the Koran... translated into Farsi...
though admittedly you are more likely to get snippets of dialogue
from "Gilligan's Island".
 
C

CBFalconer

infobahn said:
printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */

UB, due to lack of prototype for printf, and appearing outside of
the body of a function.
 
K

Keith Thompson

infobahn said:
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, or a null pointer, or a pointer to non-modifiable
storage when the corresponding parameter is not const-qualified)
or a type (after promotion) not expected by a function with
variable number of arguments, the behavior is undefined.

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.

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.

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.

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

Still, I think this calls for a DR.
 
A

aegis

Keith said:
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, or a null pointer, or a pointer to non-modifiable
storage when the corresponding parameter is not const-qualified)
or a type (after promotion) not expected by a function with
variable number of arguments, the behavior is undefined.

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.

Is (void *)0 a null pointer? I thought it was a null pointer constant.
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.

Yes. I think so too. But the example involves a null pointer constant.
On the other hand, the same reasoning could imply that strlen(NULL)
doesn't invoke undefined behavior. We have to use common sense to

strlen expects a valid string. NULL is no such thing.
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.

No. Because a null pointer constant is different from a null pointer.

char *p = NULL;

'p' is a null pointer.

But (void *)0 is a null pointer constant in the example above.

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 don't.
San Diego Supercomputer Center <*>
We must do something. This is something. Therefore, we must do
this.
 
P

Peter Nilsson

answer. */

What is _your_ theory? In other words, what leads you to question this
in the first place?

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

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, or a null pointer, or a pointer to non-modifiable
storage when the corresponding parameter is not const-qualified)
or a type (after promotion) not expected by a function with
variable number of arguments, the behavior is undefined.

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.

Since when was a pointer not allowed to be a null pointer in it's own
right?
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.

On the other hand, the same reasoning could imply that strlen(NULL)
doesn't invoke undefined behavior.

Since strlen 'computes the length of _a string_', it's clear that a
null pointer is invalid.
Still, I think this calls for a DR.

I say nay. ;)
 
P

Peter Nilsson

CBFalconer said:
answer. */

UB, due to lack of prototype for printf, and appearing outside of
the body of a function.

I'm not convinced there's anything worth discussing in the OP's post,
but your reply is "...100% correct and 0% helpful."
 
I

infobahn

[I haven't seen Keith's reply to my original question, except in
this reply-to-reply.]

That's part of what worries me.

And that's the rest of what worries me.


Yes, that's part of my concern.

And that's the other part.
Is (void *)0 a null pointer? I thought it was a null pointer constant.

If it worries you, pretend I said:

#include <stdio.h>
int main(void)
{
int *p = NULL;
printf("%p\n", (void *)p);
return 0;
}

The problem I have with this rationalisation is that it sounds too
much like rationalisation. I can hear Herbert Schildt saying "It
doesn't say you can't!", and that worries me.

Or at least a clarification from the Great Powers, complete with C&V.
 
K

Keith Thompson

aegis said:
answer. */ [snip]

Is (void *)0 a null pointer? I thought it was a null pointer constant.

Yes, it's a null pointer constant, which is a source construct. A
null pointer is a value that exists at run time. In the function call
above, a null pointer is passed as an argument to printf. (That's
what null pointer constants are for, after all.)
Yes. I think so too. But the example involves a null pointer constant.

Which results in a null pointer at run time.
strlen expects a valid string. NULL is no such thing.

One could argue that printf("%p", ...) expects a valid pointer, and
that NULL is not a valid pointer. The wording of the standard doesn't
exclude that interpretation.
No. Because a null pointer constant is different from a null pointer.

That has nothing to do with it.

[snip]
 
K

Keith Thompson

infobahn said:
[I haven't seen Keith's reply to my original question, except in
this reply-to-reply.]

Perhaps because aegis cross-posted his reply to comp.lang.c and
comp.std.c (the original article was posted only to comp.lang.c).
 
I

infobahn

Peter said:
(Cute.)


I'm not convinced there's anything worth discussing in the OP's post,

The point is this: I have written a routine which takes T **p,
frees the memory pointed to by *p, and sets *p to NULL. In a
demo driver routine, I am trying to show that the pointer is now
NULL, using printf. When gcc showed me "(nil)" instead of something
more - well - more pointery!, I was reminded of the way it responds
to a %s/NULL match, and this concerned me, since I know perfectly
well that %s/NULL is undefined, so I was naturally concerned to
know whether %p/NULL is undefined too. It may be that the goal of
avoiding undefined behaviour is not worth discussing in comp.lang.c
but, if that is the case, why do we spend so much time discussing
precisely that? :)
but [CBFalconer's] reply is "...100% correct and 0% helpful."

Indeed. I haven't seen his reply except as quoted by your own, but
it seems a rather strange reply to make. I expected better of him.
 
R

Richard Kettlewell

"such as" introduces examples, not definitions. I think your 'escape
clause' is the natural reading.
 
P

pete

Keith said:
One could argue that printf("%p", ...) expects a valid pointer, and
that NULL is not a valid pointer. The wording of the standard doesn't
exclude that interpretation.

Whether or not NULL is an invalid pointer, depends on context.
free(NULL) is defined.
You can't just say that NULL is an invalid pointer,
without saying invalid for what purpose.
An indeterminate pointer, on the other hand, is just an invalid pointer.
 
C

CBFalconer

infobahn said:
Peter said:
(Cute.)


I'm not convinced there's anything worth discussing in the OP's post,

The point is this: I have written a routine which takes T **p,
frees the memory pointed to by *p, and sets *p to NULL. In a
demo driver routine, I am trying to show that the pointer is now
NULL, using printf. When gcc showed me "(nil)" instead of something
more - well - more pointery!, I was reminded of the way it responds
to a %s/NULL match, and this concerned me, since I know perfectly
well that %s/NULL is undefined, so I was naturally concerned to
know whether %p/NULL is undefined too. It may be that the goal of
avoiding undefined behaviour is not worth discussing in comp.lang.c
but, if that is the case, why do we spend so much time discussing
precisely that? :)
but [CBFalconer's] reply is "...100% correct and 0% helpful."

Indeed. I haven't seen his reply except as quoted by your own, but
it seems a rather strange reply to make. I expected better of him.

Well, I expected better of infobahn :) 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. If the standard
does allow problems to arise I consider that a defect in the
standard. And "(nil)" is a representation of a NULL pointer
value. Various gcc oriented printf packages do this in a variety
of situations, which is probably superior to blowing up the barn
door and releasing all the differently colored horses.
 
I

infobahn

CBFalconer said:
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.

Sometimes, yes, and other times, no. Since you seem so confident that
it's okay to pass NULL to printf when matching with %p, perhaps you
could explain the reasons for your confidence, citing relevant C&V.
After all, if this were as clear-cut to me as it is to you, I would
not have bothered asking the question; I'd like to be as convinced as
you are, but I cannot find justification in the Standard for having
that level of conviction in the "well-definedness" of the construct.

If the standard
does allow problems to arise I consider that a defect in the
standard.

You are certainly entitled to take that view, but don't forget that
(wise!) implementors use the text of the Standard when writing their
implementations. If the Standard allows them to assume they will not
be passed NULL to match a %p, then all bets are off, whether that is
a defect in the Standard or not. That is why I am concerned.

I'd rather *know* that the behaviour is, or is not, undefined
according to the text of the Standard, so that I can take appropriate
precautions in my code if need be, than rely on "gut feel" as you
seem to be suggesting.
 
C

CBFalconer

infobahn said:
Sometimes, yes, and other times, no. Since you seem so confident that
it's okay to pass NULL to printf when matching with %p, perhaps you
could explain the reasons for your confidence, citing relevant C&V.
After all, if this were as clear-cut to me as it is to you, I would
not have bothered asking the question; I'd like to be as convinced as
you are, but I cannot find justification in the Standard for having
that level of conviction in the "well-definedness" of the construct.

I can't justify my attitude, and you are entitled to yours. I
simply can't conceive of a sane implementor creating a difficulty
with this.

The clib package I use here with gcc spits out (nil) for
'printf("%s",NULL);', and I would be extremely leery of expecting
that to happen anywhere else. If you are worried about the %p
operation you can always write:

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

which is what I suspect happens within your systems printf code
whenever a pointer is expected. You just can't count on it.
 
A

Andrey Tarasevich

pete said:
...

Whether or not NULL is an invalid pointer, depends on context.
free(NULL) is defined.
You can't just say that NULL is an invalid pointer,
without saying invalid for what purpose.
An indeterminate pointer, on the other hand, is just an invalid pointer.
...

This has already been covered above. Once again, the standard says that
null pointer arguments can be specifically allowed by the specification
of the concrete function from the standard library. 'free' function is a
good example of such function: its specification explicitly states that
passing a null pointer to it is OK (does noting). The specification of
'printf' does not say that passing null pointers to it is OK. That's
exactly what constitutes the problem.
 
Q

Quentarez

printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */

I, personally, would not consider this to be UB.

I don't have supreme knowledge of the standard, nor do I have any
references to the standard to support this claim.

I decided to take a different route, and see what the compiler does with a
NULL pointer. I tested it on two compilers: MSVC6 and gcc 3.3.5.

It has already been shown previous to this post that (void *)0 is indeed a
way to get a NULL pointer, so I will refer to it as a NULL pointer from now
on.

From what I've learned, a pointer always points /somewhere/, even if that
somewhere is not where you intended.

From simply compiling and running the given code, I get the output 00000000
on MSVC6 and (nil) on gcc.

Next, I did this:

int *p = NULL;

and used my debuggers to examine the contents of p after it had been
initialized. On MSVC6 it was 0x00000000. On gcc it was 0x0.

%p prints out an address, and, from what I see, a NULL pointer has a valid
address.

Based on my observations, it seems that

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

is not UB.
 

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,769
Messages
2,569,577
Members
45,052
Latest member
LucyCarper

Latest Threads

Top