%p and casting

J

Jack Klein

Richard Heathfield said:
The representations of char * and void * are so closely related [...]

In fact, they are so closely related that they are required to be
the same:

A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.

(C99 6.2.5#26)

Yes, of course, and this has been true since ANSI89/ISO90.

But there is neither requirement nor guarantee in the standard that
pointer to void and pointer to char are passed to functions in the
same way, whether the functions are variadic or not.

gcc is taking advantage of its knowledge that it passes pointer to
void and pointer to char in the same way, and therefore the result
will be identical.

I doubt that there are many, or even any, implementations that pass
the two pointer types differently but nothing in the standard forbids
it, and such an implementation would be conforming.

So the behavior is undefined, as the standard says about all
mismatches between *printf() conversion specifiers and arguments.

As we often maintain here, even the fact that every single compiler in
existence, past present and future, performs exactly the same for a
specific instance of undefined behavior does not make the behavior
defined.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
B

Ben Pfaff

Jack Klein said:
Richard Heathfield said:
The representations of char * and void * are so closely related [...]

In fact, they are so closely related that they are required to be
the same:

A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.

(C99 6.2.5#26)

Yes, of course, and this has been true since ANSI89/ISO90.

For the record, I wasn't trying to contradict the fact that
passing a char * to %p is undefined behavior. The Standard says
%p has to have a void * argument, and so it must.

GCC doesn't complain about exchanging char * and void * probably
because it will always work for GCC-compiled code. Complaining
about such would probably just annoy most programmers and thus
they'd just turn off the warning instead than fixing the code,
which would be unproductive due to all of the other benefits that
such warnings have. In the end, I think it's better that GCC
doesn't complain.
 
M

Malcolm

Ben Pfaff said:
GCC doesn't complain about exchanging char * and void * probably
because it will always work for GCC-compiled code. Complaining
about such would probably just annoy most programmers and thus
they'd just turn off the warning instead than fixing the code,
which would be unproductive due to all of the other benefits that
such warnings have. In the end, I think it's better that GCC
doesn't complain.
The other factor is that the %p format specifier obviously isn't intended to
provide output to the user. It is for debugging, and generally programmers
will know what platform they are debugging on, and delete the function call
after the bug is found.
 
A

Arthur J. O'Dwyer

The representations of char * and void * are so closely related [...]

In fact, they are so closely related that they are required to be
the same:

A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.

Yes, of course, and this has been true since ANSI89/ISO90.

But there is neither requirement nor guarantee in the standard that
pointer to void and pointer to char are passed to functions in the
same way, whether the functions are variadic or not.[/QUOTE]

Oh -- I had completely overlooked this aspect of it. So, while
I still think the ambiguity I mentioned crossthread in N869 is a
little weird, you've just pointed out that

printf("%p", p);

is undefined behavior no matter *which* pointer to character type
matches (void *) in representation! Thanks.

Followup question, though: Does the (void *) <-> ([FOO] char *)
similarity then have *any* practical application in portable
code?

(where [FOO] == 'signed', 'unsigned', or nothing, or any combination
of the above, depending on how you read 6.2.5#25...)

-Arthur
 
S

Serve La

Hallvard B Furuseth said:
Pointers to different types can have different representations. For
example, a pointer to an 'int' may contain the 'word number' for the
memory location containing that int, while a pointer to a 'void' may
contain its 'byte number'. In that case, to convert an int* to a void*,
the representation of the int* pointer must be multiplied with the
number of bytes in an int.

So if I understand you correctly, in some situations a compiler generates
extra code for the following?

void *x = malloc(3 * sizeof(int));
// other code .....
int *y = x;
 
H

Hallvard B Furuseth

Serve said:
So if I understand you correctly, in some situations a compiler generates
extra code for the following?

void *x = malloc(3 * sizeof(int));
// other code .....
int *y = x;

For the 'int *y = x;' assigment, yes.
 
R

Richard Heathfield

Irrwahn said:
Hm, I tend to agree with ED,

That's the safe option, and it's a sensible place to stand. But as you might
have seen from elsethread, the issue isn't quite as clear-cut as it seems.
Casting, in this case, is the Right Thing, whether or not it is strictly
necessary for char *.
Please correct me if I'm wrong.

There is no consensus on the matter. You might be right, or you might be
wrong. You have chosen the safest interpretation, though; wise move.
 
A

Arthur J. O'Dwyer

That's the safe option, and it's a sensible place to stand. But as you might
have seen from elsethread, the issue isn't quite as clear-cut as it seems.
Casting, in this case, is the Right Thing, whether or not it is strictly
necessary for char *.

There is no consensus on the matter. You might be right, or you might be
wrong. You have chosen the safest interpretation, though; wise move.


Jack Klein wrote, cross-thread:
But there is neither requirement nor guarantee in the standard that
pointer to void and pointer to char are passed to functions in the
same way, whether the functions are variadic or not.

Richard, do you see something I don't? If my pet implementation
decides to pass (char *)s in Register One and (void *)s in Register
Two, and I forget the cast in 'printf', then don't I get weird
answers, and rightfully so?

I think the cast is *always* required (for correct code), no matter
the alignment or representation issues.

-Arthur
 
R

Richard Heathfield

Arthur said:
Jack Klein wrote, cross-thread:

Richard, do you see something I don't? If my pet implementation
decides to pass (char *)s in Register One and (void *)s in Register
Two, and I forget the cast in 'printf', then don't I get weird
answers, and rightfully so?

Let me first say that the cast is clearly the Right Thing, because we know
that the cast guarantees the code, whereas an implicit conversion relies on
a subtle and possibly incorrect interpretation of the Standard.

Having said that, if char * and void * are passed in different registers,
does that make their representation different? I don't know, because I
can't find a normative definition of "representation" in the Standard. An
ordinary interpretation of "representation" as "bit pattern", if correct,
would of course render this suggestion laughable, provided such an
interpretation could be backed up with normative text. (And, in fairness to
your point of view, the Standard does appear to use "representation" mainly
(or possibly solely) in the context of bit patterns.) But if it /does/ mean
their representation is different, then would not such an implementation be
non-conforming?
I think the cast is *always* required (for correct code), no matter
the alignment or representation issues.

I think it's always wise. It may well be that it's always required, which is
why it's wise! But I do recall some rather heated debate on this very
matter a year or three ago, with heavyweights pitching in on both sides,
and I don't think it was ever satisfactorily resolved.
 
M

Martin Dickopp

Richard Heathfield said:
Having said that, if char * and void * are passed in different
registers, does that make their representation different?

Not necessarily, according to my understanding of the standard.
I don't know, because I can't find a normative definition of
"representation" in the Standard.

Chapter 6.2.6 (entitled "Representations of types") contains a definition
of the "object representation of [a] value" in section 6.2.6.1#4. I think
this object representation is what is meant by "representation" in this
discussion.

Martin
 
R

Richard Heathfield

Martin said:
Not necessarily, according to my understanding of the standard.

Right. Not necessarily.
I don't know, because I can't find a normative definition of
"representation" in the Standard.

Chapter 6.2.6 (entitled "Representations of types") contains a definition
of the "object representation of [a] value" in section 6.2.6.1#4. I think
this object representation is what is meant by "representation" in this
discussion.

I think you're probably right. I just don't happen to know for sure.
 
K

Kevin Easton

Richard Heathfield said:
Right. Not necessarily.

Richard, I think the representation issue is a red herring in the
specific case of printf() (though it may be relevant in the context of
variadic functions you write yourself). The standard says, in a very
clear and unambigous manner, when descripting the printf conversion
specifiers:

p The argument shall be a pointer to void.


No ifs, ands or buts - in the case of printf with the %p format, the
argument shall be a pointer to void. It's a specific clause overriding
all the more general ones about object representations and so forth.

- Kevin.
 
R

Richard Heathfield

Kevin said:
Richard, I think the representation issue is a red herring in the
specific case of printf() (though it may be relevant in the context of
variadic functions you write yourself). The standard says, in a very
clear and unambigous manner, when descripting the printf conversion
specifiers:

p The argument shall be a pointer to void.

Ah, it's tricky to argue with that. :)
No ifs, ands or buts - in the case of printf with the %p format, the
argument shall be a pointer to void. It's a specific clause overriding
all the more general ones about object representations and so forth.

I can't see any rational way to disagree with that. I wonder why it wasn't
raised in the earlier thread? (Or perhaps it was and nobody noticed.)

Your citation strongly (indeed, canonically) reinforces what I'm sure most
of us considered best practice anyway.
 

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
474,079
Messages
2,570,574
Members
47,207
Latest member
HelenaCani

Latest Threads

Top