Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

printf("%p") and casting to (void *)

Tags:

In a recent question, someone mentioned that when printing a pointer value with printf, the caller must cast the pointer to void *, like so:

int *my_ptr = ....  printf("My pointer is: %p", (void *)my_ptr); 

For the life of me I can't figure out why. I found this question, which is almost the same. The answer to question is correct - it explains that ints and pointers are not necessarily the same length.

This is, of course, true, but when I already have a pointer, like in the case above, why should I cast from int * to void *? When is an int * different from a void *? In fact, when does (void *)my_ptr generate any machine code that's different from simply my_ptr?

UPDATE: Multiple knowledgeable responders quoted the standard, saying passing the wrong type may result in undefined behavior. How? I expect printf("%p", (int *)ptr) and printf("%p", (void *)ptr) to generate the exact same stack-frame. When will the two calls generate different stack frames?

like image 764
zmbq Avatar asked Jul 21 '14 14:07

zmbq


People also ask

What does printf %P do?

This is used to print the pointer type data.

Can we use printf for casting?

indicates that anything can follow, and by the rules of C, you can pass anything to printf as long as you include a format string. C simply does not have any constructs to describe any restrictions for the types of objects passed. This is why you must use casts so that the objects passed have exactly the needed type.

Can you printf a pointer?

You can print a pointer value using printf with the %p format specifier. To do so, you should convert the pointer to type void * first using a cast (see below for void * pointers), although on machines that don't have different representations for different pointer types, this may not be necessary.


2 Answers

The %p conversion specifier requires an argument of type void *. If you don't pass an argument of type void *, the function call invokes undefined behavior.

From the C Standard (C11, 7.21.6.1p8 Formatted input/output functions):

"p - The argument shall be a pointer to void."

Pointer types in C are not required to have the same size or the same representation.

An example of an implementation with different pointer types representation is Cray PVP where the representation of pointer types is 64-bit for void * and char * but 32-bit for the other pointer types.

See "Cray C/C++ Reference Manual", Table 3. in "9.1.2.2" http://docs.cray.com/books/004-2179-003/004-2179-003-manual.pdf

like image 125
ouah Avatar answered Sep 23 '22 05:09

ouah


In C language all pointer types potentially differ in their representations. So, yes, int * is different from void *. A real-life platform that would illustrate this difference might be difficult (or impossible) to find, but at the conceptual level the difference is still there.

In other words, in general case different pointer types have different representations. int * is different from void * and different from double *. The fact that your platform uses the same representation for void * and int * is nothing more than a coincidence, as far as C language is concerned.

The language states that some pointer types are required to have identical representations, which includes void * vs. char *, pointers to different struct types or, say, int * and const int *. But these are just exceptions from the general rule.

like image 23
AnT Avatar answered Sep 23 '22 05:09

AnT