%p and casting

1

127.0.0.1

Hello!

#include <stdio.h>

int main(void)
{
char *p = "hello, world";

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

return 0;
}

Why doesn't GCC 3.2 issue a diagnostic when I compile the above code with
'-W -Wall -ansi -pedantic -O'? How is char * different from int * or double
*, which cause a 'warning: void format, different type arg (arg 2)'
diagnostic?

Many thanks
 
S

Simon Biber

127.0.0.1 said:
#include <stdio.h>

int main(void)
{
char *p = "hello, world";

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

return 0;
}

Why doesn't GCC 3.2 issue a diagnostic when I compile the above code with
'-W -Wall -ansi -pedantic -O'? How is char * different from int * or double
*, which cause a 'warning: void format, different type arg (arg 2)'
diagnostic?

There is no requirement for any compiler to produce any diagnostic for
the given code. There is undefined behaviour, but no constraint
violation.

The fact that 'gcc -W -Wall -ansi -pedantic -O' does produce a diagnostic
for some pointer types and does not for some other pointer types is
irrelevant and off-topic on comp.lang.c.
 
H

Hallvard B Furuseth

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.

In normal assignments and in function calls using prototypes, the
compiler takes care of this for you. With one exception: arguments
passed to functions with a variable number of arguments, like printf.
In this case the prototype doesn't say which type the function expects,
so the compiler can't convert it for you. gcc knows what the %p format
means, though, and warns you about it.
The fact that 'gcc -W -Wall -ansi -pedantic -O' does produce a
diagnostic for some pointer types and does not for some other pointer
types is irrelevant and off-topic on comp.lang.c.

Nuts. Compilers usually have reasons for what they do. In this case, its
reason is on-topic: As you say, it's undefined behaviour.
 
R

Richard Heathfield

127.0.0.1 said:
Hello!

#include <stdio.h>

int main(void)
{
char *p = "hello, world";

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

return 0;
}

Why doesn't GCC 3.2 issue a diagnostic when I compile the above code with
'-W -Wall -ansi -pedantic -O'? How is char * different from int * or
double *, which cause a 'warning: void format, different type arg (arg 2)'
diagnostic?

The representations of char * and void * are so closely related that there
is actually some dispute as to whether the behaviour of your program is
well-defined.

To be safe, add the cast to (void *) anyway, just as you do when you print
any object pointer's value.
 
E

Emmanuel Delahaye

127.0.0.1 said:
#include <stdio.h>

int main(void)
{
char *p = "hello, world";

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

return 0;
}

Why doesn't GCC 3.2 issue a diagnostic when I compile the above code with
'-W -Wall -ansi -pedantic -O'? How is char * different from int * or double
*, which cause a 'warning: void format, different type arg (arg 2)'
diagnostic?

"%p" expects a (void*). This is what gcc is trying to say to you.

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

Simon Biber

Hallvard B Furuseth said:
Nuts. Compilers usually have reasons for what they do. In this case,
its reason is on-topic: As you say, it's undefined behaviour.

Yes, it's undefined behaviour for any type except a pointer to void.

The point the OP made is that gcc does NOT warn when the argument is a
pointer to char, but DOES warn for other pointer types, eg. (int *),
(double *).

The compiler probably has a reason for that, but according to the standard
it's equally undefined behaviour for (char *), (int *) or (double *), yet
gcc behaves differently for char* than for int* or double*.
 
E

Edd Dawson

127.0.0.1 said:
Hello!

#include <stdio.h>

int main(void)
{
char *p = "hello, world";

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

return 0;
}

Why doesn't GCC 3.2 issue a diagnostic when I compile the above code with
'-W -Wall -ansi -pedantic -O'? How is char * different from int * or double
*, which cause a 'warning: void format, different type arg (arg 2)'
diagnostic?

I think in the ANSI C standard you can set void pointers to the value
of pointers to other types (and vice versa) without cast. So you
shouldn't get a warning.

Edd
 
M

Mantorok Redgormor

127.0.0.1 said:
Hello!

#include <stdio.h>

int main(void)
{
char *p = "hello, world";

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

return 0;
}

Why doesn't GCC 3.2 issue a diagnostic when I compile the above code with
'-W -Wall -ansi -pedantic -O'? How is char * different from int * or double
*, which cause a 'warning: void format, different type arg (arg 2)'
diagnostic?

Many thanks

The standard says: 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.

You should use printf("%p\n", (void **)p); I guess.
 
E

Emmanuel Delahaye

In said:
The standard says: 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.

You should use printf("%p\n", (void **)p); I guess.

ITYM:

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

Tom Zych

Mantorok said:
The standard says: 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.
You should use printf("%p\n", (void **)p); I guess.

I think you're looking at the spec for fscanf, not fprintf. *printf
takes void *.
 
S

Simon Biber

Edd Dawson said:
I think in the ANSI C standard you can set void pointers to the value
of pointers to other types (and vice versa) without cast. So you
shouldn't get a warning.

You can convert between pointer to void and any other pointer to object
type without a cast. However, that conversion is not applied for the
variable arguments of a function such as printf. It is wrong to pass the
wrong type to any printf. The only correct type for the "%p" specifier
is pointer to void.
 
I

Irrwahn Grausewitz

I think in the ANSI C standard you can set void pointers to the value
of pointers to other types (and vice versa) without cast. So you
shouldn't get a warning.

Disagreed: no implicit casting takes place here. One has to explicitely
cast the pointer-to-whatever to a pointer-to-void in above example.

Regards

Irrwahn
--
do not write: void main(...)
do not use gets()
do not cast the return value of malloc()
do not fflush( stdin )
read the c.l.c-faq: http://www.eskimo.com/~scs/C-faq/top.html
 
R

Richard Heathfield

Emmanuel said:
It invokes an undefined behaviour.

Chapter and verse please, assuming that p is of type char * and that a valid
printf prototype is in scope.
 
I

Irrwahn Grausewitz

Richard Heathfield said:
Chapter and verse please, assuming that p is of type char * and that a valid
printf prototype is in scope.

Hm, I tend to agree with ED, but maybe I misunderstood the following
(quoted from n843):

7.19.6.1 The fprintf function
[...]
[#8] The conversion specifiers and their meanings are:
[...]
p The argument shall be a pointer to void. The value
of the pointer is converted to a sequence of
printable characters, in an implementation-defined
manner.
[...]
[#9] [...] If any argument is not the correct type
for the corresponding coversion specification, the behavior
is undefined.

IMHO this leads to:

#include <stdio.h>

int main(void)
{
char *p;
printf( "%p\n", p ); /* undefined behaviour! */
return 0;
}

Please correct me if I'm wrong.

Regards

Irrwahn
 
A

Arthur J. O'Dwyer

Chapter and verse please, assuming that p is of type char * and
that a valid printf prototype is in scope.

For those who don't remember the previous discussions on this
topic, here's the relevant C&V.

N869 6.2.5
[#15] The three types char, signed char, and unsigned char
are collectively called the character types. The
implementation shall define char to have the same range,
representation, and behavior as either signed char or
unsigned char.

N869 6.2.5
[#27] A pointer to void shall have the same representation
and alignment requirements as a pointer to a character type.


Now, the wording of #27 is ambiguous, because of the use of the
word "a". For example, consider the following English sentences:

"A tin of food can feed a dog."
"I have a dog."

In the first case, "a" means "any" -- any tin of food can feed any
dog at all. In the second case, "a" means "some particular one" --
I have *one* dog. It's *not* true that for any dog at all, I have
it!

So we have the ambiguity. Either #27 means

A pointer to void [is basically interchangeable with]
a pointer to any character type at all

or else it means

A pointer to void [is basically interchangeable with]
a pointer to some particular [unspecified] character type


Obviously, the two interpretations lead to different results in
this case; if (void *) and (char *) have the same representation,
then printf("%p", cptr) is well-defined, and if they don't (e.g.,
if (void *) and (unsigned char *) have the same representation,
and char is signed), then printf("%p", p) is undefined.

I don't know what has been done since N869 to disambiguate this
section.

-Arthur
 
J

Joona I Palaste

Arthur J. O'Dwyer said:
For those who don't remember the previous discussions on this
topic, here's the relevant C&V.
N869 6.2.5
[#15] The three types char, signed char, and unsigned char
are collectively called the character types. The
implementation shall define char to have the same range,
representation, and behavior as either signed char or
unsigned char.
N869 6.2.5
[#27] A pointer to void shall have the same representation
and alignment requirements as a pointer to a character type.

Now, the wording of #27 is ambiguous, because of the use of the
word "a". For example, consider the following English sentences:
"A tin of food can feed a dog."
"I have a dog."
In the first case, "a" means "any" -- any tin of food can feed any
dog at all. In the second case, "a" means "some particular one" --
I have *one* dog. It's *not* true that for any dog at all, I have
it!
So we have the ambiguity. Either #27 means
A pointer to void [is basically interchangeable with]
a pointer to any character type at all
or else it means
A pointer to void [is basically interchangeable with]
a pointer to some particular [unspecified] character type

Obviously, the two interpretations lead to different results in
this case; if (void *) and (char *) have the same representation,
then printf("%p", cptr) is well-defined, and if they don't (e.g.,
if (void *) and (unsigned char *) have the same representation,
and char is signed), then printf("%p", p) is undefined.
I don't know what has been done since N869 to disambiguate this
section.

This is something which relates to an ambiguity often found in
dictionaries.
Consider this kind of entry:

zyzzyva
n. A small, brownish weevil that feeds on crops.

Does this mean that any small, brownish weevil that feeds on crops is
a zyzzyva? It most likely does NOT, but there's no way to tell without
having knowledge outside of the dictionary.

--
/-- Joona Palaste ([email protected]) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"I wish someone we knew would die so we could leave them flowers."
- A 6-year-old girl, upon seeing flowers in a cemetery
 
B

Ben Pfaff

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)
 

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,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top