What is difference between %d and %p when printing?
For example:
int main() {
int a = 9;
printf("%d\n", &a);
printf("%p\n", &a);
return 0;
}
The printf function supports different conversions for different types of arguments: %d produces a decimal representation (d for decimal) for an argument of type int, %p produces a system dependent representation of a void pointer (p for pointer)
There are multiple problems in your code:
you pass the address of an int variable, hence a type int * where printf expects an int for the %d conversion: This has undefined behavior
you pass the address of an int variable, hence a type int * where printf expects an void * for the %p conversion: This has undefined behavior
you did not include <stdio.h> and you call the function printf without a proper prototype: the prototype inferred from the call is incompatible with the actual definition, so the behavior is undefined.
The output you observe is the result of undefined behavior: it is unpredictable and potentially irreproducible: on my system, I get different output every time I run the program, even without recompiling. Undefined behavior means anything can happen.
Here is a modified version:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main() {
int a = 9;
printf("%d\n", a);
printf("%p\n", (void *)&a);
printf("0x%"PRIxPTR"\n", (uintptr_t)&a);
printf("%p\n", (void *)NULL);
printf("0x%"PRIxPTR"\n", (uintptr_t)NULL);
return 0;
}
Output:
9
0x7fff54823844
0x7fff54823844
0x0
0x0
The last conversion takes a uintptr_t, an integer type large enough to store an integer representation of a pointer. On my system, OS/X, the %p conversion produces the same output as 0x%x for the corresponding integer type.
Will output something like:
-1807747332,
00000083943ff6fc
The format specifier converts the value of the corresponding variable to the format data type. %d converted it to a signed integer. If you use %p it simply treats the value as the memory address of a pointer and prints it in hexadecimal.
Related
This question already has answers here:
printf("%p") and casting to (void *)
(7 answers)
Closed 5 years ago.
What does (void*) mean in the following code? I tried removing (void*) typecast but it still works just fine and prints the address of usrInt variable. Can you explain this, please?
#include <stdio.h>
int main(void) {
int usrInt = 0; // User defined int value
int* myPtr = NULL; // Pointer to the user defined int value
// Prompt user for input
printf("Enter any number: ");
scanf("%d", &usrInt);
// Output int value and location
printf("We wrote your number into variable usrInt.\n");
printf("The content of usrInt is: %d.\n", usrInt);
printf("usrInt's memory address is: %p.\n", (void*) &usrInt);
printf("\nWe can store that address into pointer variable myPtr.\n");
// Grab location storing user value
myPtr = &usrInt;
// Output pointer value and value pointed by pointer
printf("The content of myPtr is: %p.\n", (void*) myPtr);
printf("The content of what myPtr points to is: %d.\n", *myPtr);
return 0;
}
Normally, a cast to or from void * is simply redundant, because this conversion is implicit in C for any data pointer type.
Passing a pointer to a variadic function is a special case that requires the cast.
printf() is a variadic function. The printf() prototype looks like this:
int printf(const char *format, ...);
This means the compiler doesn't see any type declarations for parameters that come after format. Therefore, it doesn't know the type passed should be void *, so the conversion doesn't happen automatically.
Often, omitting the cast won't have any visible effect because in most implementations, all pointers have the exact same internal representation. But the C standard doesn't guarantee that, so implementations are possible where e.g. an int * would have a different representation when it is converted to a void *. If you omit the cast, your code is technically incorrect (it invokes undefined behavior for passing the wrong type for the conversion %p) and would lead to wrong results on platforms where representations of pointers to different types are different.
c11: 7.21.6 Formatted input/output functions (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.
I have the following program.
#include<stdio.h>
int main()
{
char a='b';
int b=11299;
char d[4]="abc";
printf("value of a is %d\n",a);
printf("value of b is %c\n",b);
printf("value of c is %d\n",*d);
char *c=d;
c=c+1;
printf("c is %d\n",*c);
}
I am little confused with %d format specifier. I was thinking that it would print 4 bytes of data. But from the above program (first and last printf) it is evident that it prints only one byte when a char parameter is used. Why does %d print only one byte? How does it know how many bytes to print?
It doesn't print bytes; it prints values -- the value you pass as the corresponding argument -- provided the value passed has the right type.
In your example 1, the argument is the value 'b'. It initially has type char (because the expression a has type char) but variadic arguments are subject to default promotions, which promote any integer type with lower rank than int up to int. Thus, as an argument, the type is int.
In your example 3, the argument is the value 'a'. Likewise it initially has type char (because the expression *d has type char) but it gets promoted to int.
If promotions didn't happen and the types were wrong, though, printf still wouldn't "print fewer bytes". Your program would just have undefined behavior (so anything could happen). For example:
int a = 42;
printf("%lld\n", a); // undefined behavior because int does not
// get promoted implicitly to long long.
In your example 2, the %c format specifier expects an argument of type int; printf converts it to unsigned char and prints the corresponding character. Any value of int is acceptable; it doesn't have to already be a value in the range of unsigned char.
First, you're probably declaration specifying the ISO C90, and this forbids mixed declarations and code, as shown in the warning.
The statement pointer of type char c varible char * c = d; must be made for example of the statement string d char d [4] = "abc"; and not in the middle of the code.
Second: int main (){ function does not return anything, but this must specify to not pull warning.
The revised program would be:
#include<stdio.h>
int main()
{
char a='b';
int b=11299;
char d[4]="abc";
char *c=d;
printf("value of a is %d\n",a);
printf("value of b is %c\n",b);
printf("value of c is %d\n",*d);
c=c+1;
printf("c is %d\n",*c);
return 0;
}
...then why is the code below give same value (meatballs) for address and the actual content? And how to make sense of %d value of meatballs, is it random?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main()
{
int i;
int meatballs[5]= {1,2,3,4,5};
printf("\nmeatsballs %p %p %d \t \n",meatballs, &meatballs,
meatballs);
return 0;
}
meatballs is an array, and it has type int[5]. However C doesn't allow passing arrays by value, so array decays into pointer for function call. This is equivalent of pointer to first element of array &meatballs[0], and it has type int*.
&meatballs is a pointer to an array, and it has type int(*)[5]. Since it's a pointer it can be passed to a function.
As you can see, both 1. and 2. return same address, but they have different types: pointer to integer array vs pointer to single integer.
Note: Types void* and int* don't necessarily have the same representation(1), and for %p only valid type is void*(2) or you will get undefined behaviour(3). Always convert pointer to void* when printing addresses:
printf("%p %p", (void*)meatballs, (void*)&meatballs);
Last situation is same as first, but you are using wrong type specifier %d. Resulting type is again int* as in case 1, but it is interpreted as int. This is clear undefined behaviour, and output is garbage.
To print integer array element, use any of the following methods:
printf("%d %d %d", meatballs[i], *(meatballs + i), *meatballs);
First two will print array element at index i, and last will print first element. I recommend using the meatballs[i] in most cases, as it's most clear.
References to C standard (draft):
N1570, 6.2.5 paragraph 28
A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.48)... ...Pointers to other types need not have the same representation or alignment requirements.
N1570, 7.21.6 paragraph 8
p The argument shall be a pointer to void. ...
N1570, 7.21.6 paragraph 9
... If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
You have to use the unary dereference operator *, so that the actual value is shown as %d expects an integer.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main()
{
int i;
int meatballs[5]= {1,2,3,4,5};
printf("\nmeatsballs %p %p %d \t \n",meatballs, &meatballs,
*meatballs);
return 0;
}
Look at the last parameter: *meatballs. This code actually prints 1 as value and is the first element in your array. So your guess is right and it is only a bug.
When I compile the following code, Visual studio shows warning of C4477. Why this warning generated by visual studio? And How can I fix this code?
warning : warning C4477: 'printf' : format string '%d' requires an argument of type 'int', but variadic argument 1 has type 'int *'
#include <stdio.h>
int main(void) {
int num = 0;
int *pi = #
printf("Address of num: %d Value: %d\n", &num, num);
printf("Address of pi: %d Value: %d\n", &pi, pi);
return 0x0;
}
Because you are using incorrect format specifier. %d is to print an int. To print pointers use %p and cast to void*:
printf("Address of num: %p Value: %d\n", (void*)&num, num);
printf("Address of pi: %p Value: %p\n", (void*)&pi, (void*)pi);
The cast to void* is needed because variadic functions don't do any type conversions from type * to void * as required for %p. Quoting the standard:
7.21.6 Formatted input/output functions (C11 draft)
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.
Said another way, your argument &num (or in the form (void *) &num) is telling the compiler that you wish to pass in to the function the address of num, not the value of num. The printf function with it's %d format specifier is expected a value, not an address. The complaint is the compiler realizing this difference.
Note: in the 32 bit work, an address and an int are both 32 bits and so things (i.e. the %d) would just work. But, in the 64 bit world, an int is still 32 bits long but an address is 64 bits. I.E. you can't accurately represent the value of the pointer with a %d. That's why %p got created. It (the compiler) is smart enough to handle a %p parameter as a 32 bit quantity when compiled for 32 bits and a 64 bit quantity when compiled for 64 bits.
Read up on computer architecture, hardware stacks and their bit sizes. While you're at it you may also wish to understand the difference between little endian and big endian.
#include <stdio.h>
int main(void) {
int a[5] = {0, 1, 2, 3, 4}, *p;
p = a;
printf("%d\n%d\n%d\n%d\n%d\n", p, *p);
return 0;
}
When I executed this code, I got a negative value for p. I have studied that address cannot be negative. Then why I have got a negative value
%d is not the correct format specifier to handle a pointer (address). You should be using %p and cast the corresponding argument to void* for printing an address. Using wrong argument type for a particular format specifier invokes undefined behavior.
To quote C11 chapter ยง7.21.6.1
[...] If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
In this code, *p does not denote an address, anyway.
You cannot print an array by just using the %ds in a single format string. You need to have a loop. In your code,
printf("%d\n%d\n%d\n%d\n%d\n", p, *p);
the format string expects 5 ints as argument, while you supply only a pointer and an int. FWIW, supplying insufficient argument for supplied conversion specifiers invoke undefined behavior, too. Quoting the same standard,
[...] If there are insufficient arguments for the format, the behavior is
undefined. [...]
To elaborate, replace
printf("%d\n%d\n%d\n%d\n%d\n", p, *p);
by
for (i= 0; i < 5; i++, p++)
printf("%d %p\n", *p, (void *)p);
For pointers, use %p with printf():
int a[5] = {0, 1, 2, 3, 4}, *p;
p = a;
printf("%p\n%d", (void *)p, *p);
Also make sure your comiler warnings are at the highest level. You should get a warning for using %d with a pointer then:
warning <code>: 'printf' : '%d' in format string conflicts with argument 1 of type 'int *'
Mis-matched printf() specifiers and arguments
printf("%d\n%d\n%d\n%d\n%d\n", p, *p); expects 5 int. Code is supplying a int * and int. Result: undefined behavior.
Instead:
printf("Pointer %p\nValue: %d\n", (void *) p, *p);