Compiling the below code without gcc flags doesn’t raise any errors but does when I use -Werror
, I have been printing memory address with %p flag but apparently I now have to typecast to void*
to use the %p
flag, what’s the required flag to print integer pointers as %ls
suggested by the compiler isn’t supported in ISO C90?
int main(int argc, char *argv[]) {
int var = 789, *ptr, **ptr1;
ptr = &var;
ptr1 = &ptr;
printf("var: %dn", var);
printf("address of var: %pn", &var);
printf("address: %p references: %dn", ptr, *ptr);
return (0);
}
main.c:18:27: error: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int *’ [-Werror=format=]
18 | printf("address of var: %pn", &var);
| ~^ ~~~~
| | |
| | int *
| void *
| %ls
also using %ls format specifier:
main.c:19:21: error: ISO C90 does not support the ‘%ls’ gnu_printf format [-Werror=format=]
19 | printf("address: %ls references: %dn", ptr, *ptr);
| ^
I know I have to typecast, but why do I have to do that?
8
C has a number of implicit conversion which happen as part of an assignment, which includes passing named parameters to functions, and one of those implicit conversions is between a void *
and any other object pointer.
What makes printf
different is that it is a variadic function, where only the first parameter is named. That means that any parameters that follow don’t get converted by these implicit conversion rules.
There’s no guarantee that a void *
has the same representation as other object pointers (other than character types), so passing an int *
to printf
with the %p
format specifier might not have the expected result as the typical implicit conversion doesn’t happen.
Because of this, if a variadic parameter to a function is expected to be a void *
, as it is for the %p
format specifier, an explicit cast is required.
1
printf
requires void *
paramamters for %p
.
You need to convert other types of pointers.
printf
is well known to many compilers and they provide additional diagnostics (beyond required by C standard) when parsing the format string
printf("address: %p references: %dn", (void *)ptr, *ptr);
ISO C90 does not support the ‘%ls’
Why don’t you use wprintf
function instead of non standard format?
What is the point of using a prehistoric language standard? Would you use C# 1.0 or python 0.9.0 nowadays?
BTW you can print pointer as integer using uintptr_t
and PRIuPTR
format.
int main()
{
int var = 5
uintptr_t address = (uintptr_t)&var;
printf("Address: %" PRIuPTR "n", address);
return 0;
}