Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

printf and pointers [duplicate]

Tags:

c++

c

Possible Duplicate:
Correct format specifier to print pointer (address)?

When printing a pointer using printf, is it necessary to cast the pointer to void *? In other words, in code like

#include <stdio.h>
int main() {
    int a;
    printf("address of a = %p\n", &a);
}

should the argument really be (void *) &a? gcc doesn't seem to give any warnings when no explicit cast is made.

like image 266
Joshua Green Avatar asked Jan 29 '12 20:01

Joshua Green


3 Answers

Yes, the cast to void* is required.

int a;
printf("address of a = %p\n", &a);

&a is of type int*; printf's "%p" format requires an argument of type void*. The int* argument is not implicitly converted to void*, because the declaration of printf doesn't provide type information for parameters other than the first (the format string). All arguments after the format string have the default argument promotions applied to them; these promotions do not convert int* to void*.

The likely result is that printf sees an argument that's really of type int* and interprets it as if it were of type void*. This is type-punning, not conversion, and it has undefined behavior. It will likely happen to work if int* and void* happen to have the same representation, but the language standard does not guarantee that, even by implication. And the type-punning I described is only one possible behavior; the standard says literally nothing about what can happen.

(If you do the same thing with a non-variadic function with a visible prototype, so the compiler knows at the point of the call that the parameter is of type void*, then it will generate code to do an implicit int*-to-void* conversion. That's not the case here.)

like image 129
Keith Thompson Avatar answered Nov 17 '22 23:11

Keith Thompson


Is this a C or a C++ question? For C++, it seems that according to 5.2.2 [expr.call] paragraph 7 there isn't any implicit conversion to void*. It seems that C99's 6.5.2.2 paragraph 6 also doesn't imply any explicit promotion of pointer types. This would mean that an explicit cast to void* is required as pointer types can have different size (at least in C++): if the layout of the different pointer types isn't identical you'd end up with undefined behavior. Can someone point out where it is guaranteed that a pointer is passed with the appropriate size when using variable argument lists?

Of course, being a C++ programmer this isn't much of a problem: just don't use functions with variable number of arguments. That's not a viable approach in C, though.

like image 24
Dietmar Kühl Avatar answered Nov 17 '22 22:11

Dietmar Kühl


I think it might be necessary to cast. Are we certain that the size of pointers is always the same? I'm sure I read on stackoverflow recently that the size (or maybe just the alignment?) of a struct* can be different to that of a union*. This would suggest that one or both can be different from the size of a void*.

So even if the value doesn't change much, or at all, in the conversion, maybe the cast is needed to ensure the size of the pointer itself is correct.

In print, %p expects a void* so you should explicitly cast it. If you don't do so, and if you are lucky then the pointer size and pointer representation might save the day. But you should explicitly cast it to be certain - anything else is technically undefined behaviour.

like image 31
Aaron McDaid Avatar answered Nov 17 '22 23:11

Aaron McDaid