Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

%p format specifier needs explicit cast to void* for all types but char* in printf

I've read a lot of answers about the %p format specifier usage in C language here in Stack Overflow, but none seems to give an explanation as to why explicit cast to void* is needed for all types but char*.
I'm of course aware about the fact that this requirement to cast to or from void* is tied with the use of variadic functions (see first comment of this answer) while non-mandatory otherwise.

Here's an example :

int i;    
printf ("%p", &i);

Yields a warning about type incompatibility and that &i shall be casted to void* (as required by the standard, see again here).

Whereas this chunk of code compiles smoothly with no complaint about type casting whatsoever:

char * m = "Hello";    
printf ("%p", m);

How does that come that char* is "relieved" from this imperative?

PS: It's maybe worth adding that I work on x86_64 architecture, as pointer type size depends on it, and using gcc as compiler on linux with -W -Wall -std=c11 -pedantic compiling options.

like image 900
programmersn Avatar asked Jul 09 '18 07:07

programmersn


People also ask

What is %p format specifier?

%p is a format specifier in C Programming language, that is used to work with pointers while writing a code in C.

What is %P in C printf?

In C we have seen different format specifiers. Here we will see another format specifier called %p. This is used to print the pointer type data.

What is %p format in C?

The %p format specifier is used for printing the value of a pointer in C. This phenomenon is showed clearly in the coding example below. C. Copy #include<stdio.h> void main() { int i=100; printf("%d\n",i); int *pointer = &i; printf("%p\n",i); printf("%p",pointer); }

What is the difference between %D and %P in C?

Originally Answered: What are the actual differences between %d, %u and %p format specifiers used in C to print the memory address of a variable? As you already explained %d is used for signed integers, while %u is for unsigned integers. %p is used to print pointer addresses.


2 Answers

There is no explicit cast needed for arguments of type char*, as char * has the same representation and alignment requirement as void *.

Quoting C11, chapter §6.2.5

A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. (48) [...]

and the footnote 48)

The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.

like image 185
Sourav Ghosh Avatar answered Sep 21 '22 17:09

Sourav Ghosh


The C11 standard 6.2.5/28 says:

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

with footnote 48 being:

The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.

However 7.21.6.1 ("The fprintf function") says about %p:

The argument shall be a pointer to void.


This is apparently a contradiction. In my opinion, a sensible interpretation is to say that the intent of 6.2.5/28 is that void * and char * are in fact interchangeable as the types for function arguments which do not correspond to a prototype. (i.e. arguments to non-prototyped functions, or matching the ellipsis of a prototype of variadic function).

Apparently the compiler you're using takes a similar view.

To back this up, the specification of argument types in 7.21.6.1, if taken literally without regard to intent, has a lot of other inconsistencies that have to be disregarded in practice (e.g. it says that printf("%lx", -1); is well-defined, but printf("%u", 1); is undefined behaviour).

like image 26
M.M Avatar answered Sep 19 '22 17:09

M.M