13

I have heard that pointers should first be cast to void to ensure consistency of values across different platforms and should use %p format specifier. Why is it and what exactly are the problems?

int x=100;
int *pi=&x;
printf("value of pi is: %p",(void*)pi);
Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
Naseer
  • 4,041
  • 9
  • 36
  • 72

3 Answers3

13

printf is a variadic function and must be passed arguments of the right types. The standard says %p takes void *.

Implicit cast doesn't take place for variadic functions.

Quoting from N1570 7.21.6.1 The fprintf function

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.

Community
  • 1
  • 1
Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • Notice that the your citation is surely POSIX-specific, IIRC the standard mandates just that two different pointers have a different implementation-specific output. – Matteo Italia Nov 05 '14 at 07:31
  • Nice quoting, but in practice, how could the fact that **implicit cast doesn't take place** affect the value of the passed argument (in other words, how can a cast to `void*` make the value of `pi` any different)? – barak manos Nov 05 '14 at 16:45
  • 2
    @barakmanos C specs don't require the size of `void *` and `T *` (where T is a non-void type) to be the same. A variadic implementation may decide to push different number of bytes in case of pointer to `void` and pointer to (say) `int`. But `printf` would fetch the value of this pointer as type `void *` and will invoke undefined behavior. – Mohit Jain Nov 06 '14 at 04:27
8

Internal presentation or size of different pointer types is not necessarily same.

For example on one system sizeof(void*) may be 2, but sizeof(int*) is 1.

Since printf is variable argument function, it cannot check the types of incoming parameters. If you passed int* to it, it would read wrong number of bytes, because it expects void*.

user694733
  • 15,208
  • 2
  • 42
  • 68
8

p conversion specification in printf requires an argument of type void *. C says if you pass an argument of an other type the call invokes undefined behavior.

Besides that, pointer objects of different types are not required to have the same representation: C does not guarantee that sizeof (void *) == sizeof (int *) for example. C only guarantees that void * has the same representation as pointers to character types.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • I wouldn't say "Besides that", but rather "That's because": if #2 weren't the case, there were no reason for #1. Meaning, if all pointers would look like each other in terms of memory layout, there would be no need to specify UB for non-`void` `*`. – glglgl Nov 05 '14 at 07:36
  • @glglgl I still prefer "besides that" because in addition to C saying that *Pointers to other types need not have the same representation or alignment requirements* there is a specific C rule for `fprintf` functions that says the argument for `p` shall be a pointer `void *`. – ouah Nov 05 '14 at 07:44
  • YOu are right, but the interconntection between the two remains. – glglgl Nov 05 '14 at 07:45
  • I'm curious... could you give an example of a system or compiler where `sizeof(void*) != sizeof(T*)` (`T` being anything)? – Lucas Trzesniewski Nov 06 '14 at 08:51
  • @LucasTrzesniewski I know systems where pointer representation is different between different pointer types but I don't know any system with different sizes for different object pointer types. I would also be curious to know if such a system exists in real life. – ouah Nov 07 '14 at 00:41
  • 1
    @LucasTrzesniewski: http://stackoverflow.com/questions/916051/are-there-are-any-platforms-where-pointers-to-different-types-have-different-siz – Adam Rosenfield Nov 07 '14 at 04:53