int main()
{
int a;
int* b;
a = 40;
b = &a;
printf("the address of a is %p, and the value of a is %d \n",&a, a);
return 0;
}
I find that both (void*)&a and &a print the same thing. So why do people still add (void*)? Is it just a habit?
You use specifier %p to print address stored in pointer, and this format specifier expects type to be void * . And as &a is of type int * , cast void * is used .
The printf() format specifier %p expects a void* type pointer. Since what you are passing might not be a void* type pointer, and the standard does not mandate for all pointers to have the same format, is is important that you cast a pointer to void* before passing it to printf.
For instance:
int* a = malloc(sizeof(int));
printf("a is %p",(void*)a);
Is done as best practice incase int* and void* are not similar
C Standard says that using an incorrect specifier for an argument in printf will result in undefined behavior.
7.21.6.1 The fprintf function
If a conversion specification is invalid, the behavior is undefined. 282) If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
Since pointer to int is not the same type as pointer to void, and %p may only be used for a pointer to void and even if some other rules says that any pointer may be converted to pointer to void and back, that doesn't change the fact that the behavior is undefined, because of the quoted rule.
Firstly, different pointer types are not necessarily interchangable.
Secondly, for varargs no implicit conversion takes place as the compiler does not know the expected type.
Related
I am currently doing pointers. I have been programming for a long time, but not in C/C++. With that being said, my pointer knowledge is abysmal.
Currently, I am following a guide on YouTube and he prints the code below.
int main() {
int a = 5;
int *p;
p = &a;
printf("%d\n", p);
}
This prints successfully for him, and he sees a memory location. For me, I see the error
warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *'
From this, I expect I need to put an & in front of the p to make it print the value. But then I receive this error,
int main() {
int a = 5;
int *p;
p = &a;
printf("%d\n", &p);
}
'int', but argument 2 has type 'int **'
Where is the hole in my knowledge? Any key tips or strategies when working with this, I don't know why I find this so abstract.
Thanks,
I was expecting the value to print as expected, but instead am greeted with the error.
%d is the wrong format specifier for pointers. That may work on a more lenient or noncompliant implementation, but you should use %p to print pointer values.
Warnings are not errors. You're receiving a warning, which is not stopping your program from working, because the print specifier %d (ie printf("%d")) is for displaying integers, and you're giving it a non-integer argument of type int*.
The problem here is not with the argument, it's with the print specifier. Your attempt at a fix just changes the int* to an int**, which still does not match the format specifier %d. Use %p instead, which is the specifier for pointers, and will fix the warning, and print the address in hexadecimal notation.
You could also suppress the warning with a series of explicit casts from int* to int, but integer representations of memory addresses are generally much less used than hexadecimal representations in the first place.
Note that using wrong format specifier in printf() lead to undefined behaviour1).
The correct format specifier to print a pointer is %p format specifier.
Remember, format specifier %p expect that the argument shall be a pointer to void, so you should type cast pointer argument to void *. The correct statement to print pointer p would be:
printf("%p\n", (void *)p);
C11#7.21.6.1p9 [emphasis added]
9 If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
I'm trying to print out the value of argv at this point in my code, but when I try to compile it, I get
warning: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘char **. I'm not sure what this warning means though. Is %p not meant to be used for argv even though it's a pointer?
int main(int argc, char* argv[])
{
printf("%s%p", "argv = ", argv);
}
So why don't you cast it?
printf("argv = %p\n", (void *)argv);`
The %p pointer is specified (POSIX printf(); C11 §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.
Since char ** is not a void *, you need to do the explicit conversion. The compiler isn't allowed by the standard to do the conversion to void * for you — the ellipsis notation in the declaration of printf() means that default argument promotions occur, but that affects only the float type and integer types smaller than int (short, char, etc).
On most machines these days, that's a no-op. On the (long obsolete) machine where I learned to program in C, there weren't void * yet (too old for the standard), but the equivalent was char *, and the value of a char * address for a given memory location was different from the pointer value for any other type — the casts were not optional.
Note that I'm assuming you intend to print the value of the address. If you intend to print the contents, then there's more work to be done.
Well, not any pointer (type).
According to C11, chapter §7.21.6.1, for the %p conversion specifier,
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.
So, the argument must be of type void * (or, a char*, given they have the same alignment requirements). Any other type of pointers, must be converted through an explicit cast, as there is no default argument promotion for pointers.
Something like
printf("%s%p", "argv = ", (void *)argv);
should do.
In order to print argv and it's address you need to do
int main(int argc, char* argv[])
{
int i;
printf("address of argv = %p\n", (void *)argv);
for (i = 0; i < argc; ++i)
{
printf("%s\n", argv[i]);
}
return 0;
}
I found that we can print the pointer value with %p format specifier. N1570 7.21.6.1(p8):
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
Since the pointer to void can be converted to pointer to any other object type I'm curious would the conversion by hand is necessary. Example:
struct test_t{
int a;
}
void foo(){
struct test_t *test_ptr = malloc(sizeof(*test_ptr));
printf("Pointer test_ptr = %p\n", test_ptr);
}
Here I did not convert it to void * assuming that the compiler does this for me. Is it conforming? Or I should convert such pointers to void * on my own like
printf("Pointer test_ptr = %p\n", (void *) test_ptr);
The Standard specifies that the representation of and alignment of void * is the same as char *. It is not specified if the void * representation/alignement is must be the same as any object type.
The version with (void *) is correct, and your original code causes undefined behaviour. (You already provided the relevant Standard quote so I have no need to add further quotes).
Since the pointer to void can be converted to pointer to any other object type I'm curious would the conversion by hand is necessary
"can be" means there is potential for a conversion to happen. Such a conversion only actually happens when it was requested , with the language standard specifying which constructs request a conversion.
For the arguments to printf, only the default argument promotions are applied. There are not any other conversions.
For example,
int a = 6;
printf("%p", &a);
this would print the address of the pointer of a right?
but what if we print without &?
int a = 6;
printf("%p", a);
Can someone please tell me what it prints out?
This is undefined behavior, because %p expects a void*
printf("%p", a);
Adding an explicit conversion is allowed, but the behavior is implementation-defined:
printf("%p", (void*)a);
"Implementation-defined" means that the compiler is free to do whatever it wants when converting an int to void*. See this Q&A for exact quotes from the standard.
In many implementations you would see a pointer assigned the numeric value of int (demo 1). Other implementations would warn you that the behavior is meaningless. If you treat warnings as errors, the code would fail to compile (demo 2).
According to the C standard, it's undefined behavior to send wrong matching type argument to printf(). And int != void *, so it's undefined behavior.
Each of the following statements applies unless explicitly stated otherwise in the detailed descriptions that follow: If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or a pointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined.
Source
By the way, that why you should write printf("%p", (void *)&a);
warning: format specifies type 'void *' but the argument has type 'int *' [-Wformat-pedantic]
printf("%p", &a);
~~ ^~
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);
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.
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*.
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.