Difference b/w getting an address of variable using %p and %d - c

Here is an example
#include <stdio.h>
int main()
{
int a;
printf("%d\n",&a);
printf("%p\n",&a);
return 0;
}
======Output=======
-2054871028
0x7ffd8585280c
Do these two address point to same address in RAM ?
And how can i get the value by using each one of them, especially the second one.

%d format specifier is used to output a signed decimal integer.
From C Standard#7.21.6.1p8
d,i
The int argument is converted to signed decimal in the style [-]dddd. The precision specifies the minimum number of digits to appear; if the value being converted can be represented in fewer digits, it is expanded with leading zeros. The default precision is 1. The result of converting a zero value with a precision of zero is no characters.
%p prints the pointer.
From C Standard#7.21.6.1p8
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. [emphasis mine]
This statement
printf("%d\n",&a);
lead to undefined behavior because %d is not valid for printing a pointer.
From C Standard#7.21.6.1p9
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.

When you take the address of the variable a by writing &a, what you're really doing is generating a pointer to a.
%p is designed for printing pointers. You should use %p to print pointers.
%d is not designed for printing pointers. It tries to print their values as signed decimal, which can be confusing (as you've seen), and it may not print the entire value, on a machine where pointers are bigger than integers. (For example, if you try to print pointers with %d in most "64 bit" environments, you can get even stranger results -- and that might be part of what happened here.)
This is an easy mistake to make. Good compilers should warn you about it. Mine says "warning: format specifies type 'int' but the argument has type 'int *'".
But yes, both 0x7ffd8585280c and -2054871028 do "point to the same address in RAM", because they're both the same number, the same address. (Well, they're trying to be the same address. See footnote below.)
I'm not sure what you mean by "And how can I get the value". Are you trying to get the value of the pointer, or the value of what the pointer points to?
You've already got the value of the pointer -- it's the address 0x7ffd8585280c. And since we know it points to the variable a, we know the value it points to, too. Things will be a bit more clear if we do it like this:
int a = 5;
int *ip = &a;
printf("value of pointer: %p\n", ip);
printf("pointed-to value: %d\n", *ip);
Without the explicit pointer variable ip, we could write
int a = 5;
printf("value of pointer: %p\n", &a);
printf("pointed-to value: %d\n", *&a);
But that's pretty silly, because the last line is equivalent to the much more straightforward
printf("pointed-to value: %d\n", a);
(Taking the address of a variable with & and then grabbing the contents of the pointer using * is a no-op: it's a lot like like writing a + 1 - 1.)
Footnote: I said that 0x7ffd8585280c and -2054871028 were the same number, but they're not, they're just trying to be. 0x7ffd8585280c is really -140748133160948, and -2054871028 is really 0x8585280c, which is the lower-order 8 digits of 0x7ffd8585280c. It looks like %p on your machine is printing pointers as 48-bit values by default. I was about to be surprised by that, but then I realized my Mac does the same thing. Somehow I'd never noticed that.

Related

Why can't I use %d to print the address of a variable

#include <stdio.h>
int main()
{
int a = 10;
printf("address = %d\n ", &a);
return 0;
}
test.c:11:29: warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
printf("address = %d\n ", &a);
output if I use %d
address = -376933160
output if I use %p, this is also weird, I think I should get a positive integer instead of this?
address = 0x7ffee07004d8
I know the correct way to do this should be %p, but I see in YouTube video, people can just use %d and don't get any problems. I wonder if my setting is wrong, I am using VS code to run the program.
video example
Update
Now I am aware -376933160 is an incorrect value, but still I wonder why it just outputs a random number instead of stopping the execution ?
Format string identifiers have specific purposes. The %d identifier is for integer values, like short, int etc. long has %ld more variants as such.
You have a pointer, that holds an address. Although it is a numerical value, it's special in its purpose and should be formatted as %p, the proper way to print pointers.
Also, the size of pointers may change by architecture, so it may not be the same size as the %d identifier expects.
Regarding the different values that were printed to the screen: If you were to print the address of a variable in these two formats in the same execution, you may get again one 'positive' hex value and one 'negative' integer value. But, these values are actually the same. Almost.
The integer value representation of the variable is only the lower 32 bits of the 64 bit value, and it's negative because it is signed, and as a pointer representation (since it's an address and sign doesn't matter) it is unsigned hex value and looks positive, though both are the same value in memory (At least the 32 bits that are equal). This is happening because of different width of variable and something called "Two's complement". You can further read about it here
Note: The two values you mentioned are not the same, since you got them in different executions of the program and ASLR was on, the actual address value of a has changed between executions.
It is important to mention, even though I refer to pointers in this answer as numerical values, it is not correct to regard them as so, as they hold addresses which are their own type category (Thanks #JohnBullinger for clarifying).
Use the correct format identifier to avoid this warning, at it is informing you that you may have miss typed or used the wrong variable since it is not a regular numerical value you're trying to print, but an address.
Now I am aware -376933160 is an incorrect value, but still I wonder
why it just outputs a random number instead of stopping the execution
?
Because it is Undefined Behaviour. It does what it does. No rules.
Using the wrong format specifier is cheating the compiler. Imagine that I want to buy your old car. The price is $5000. I pay you but not in US$. If I pay £5000 you are the winner. But if I pay in drachmas 5000GDR you will not be very happy. And your behaviour will be undefined. Maybe you will chase me with the baseball bat in your hand or maybe you simply give up and accept your losses.
Same happens with the compiler and the printf function.
For the same reason you can't use %f, or %c, or anything other than %p.
%d expects its corresponding argument to have type int; if the argument doesn't have type int, then the behavior is undefined. You may get reasonable-looking output, or you may not.
On most 64-bit machines sizeof (int *) > sizeof (int). On x86 pointers are 64 bits wide while ints are 32 bits wide. If you pass a pointer as the argument for %d, printf will only pull half of the pointer value - the output is gibberish.
Now I am aware -376933160 is an incorrect value, but still I wonder why it just outputs a random number instead of stopping the execution ?
Again, you're likely only seeing the lower 32 bits of a 64-bit pointer value.
Undefined behavior does not mean "stop execution" or "print an error" or anything else - it just means that neither the compiler nor the runtime environment are required to handle the situation in any particular way.
The loss of bits and the apppearence of the minus sign provoke a warning when you do it directly:
adr.c:7:13: warning: overflow in conversion from 'long int' to 'int' changes value from '140732663858392' to '-529529640' [-Woverflow]
7 | int adr = 0x7ffee07004d8;
e07004d8 (lower 32 bits) is over 2^32. With 0x7ffe0000000a it converts to '10'.
Not a random number, and no reason to "stop execution".
Such a "cast" rarely makes sense, especially not on pointers. (Unless you take a pointer to convert it to a long just to play with it).
The compiler will generally issue a warning if there is a conversion between pointer and integer types without an explicit cast as a protection to the programmer. You can eliminate the warning by casting &a to long long int.
Depending on the system you may be able to print the decimal value if you cast it with %lld:
printf("address = %lld\n ", (long long int)&a);
However, not all systems may support ll as a valid length.

But what exactly is printed when %d is used instead of %p?

As the code shows this random, seemly trash, number printed when %d is called is spaced 'sizeof(type)' numbers of the next element of a vector.
BUT if I convert the hexadecimal address of the first element, it does not match with the number.
So if it isn't the address represented in decimals, then what this printed number exactly is?
0x7ffcd6b154c0 == 140723910431936
Whereas the printed decimal was -693021504
#include <stdio.h>
void main(){
int x[] = {2, 5}, *ptr = &x;
printf("%d\n", ptr);
printf("%p\n", ptr);
printf("\n%d %d\n", ptr, (ptr + 1));
}
It's using the D6B154C0, from the 7ffcd6b154c0 which is -693021504 as a 32 bit number.
It's a dice-roll because you invoke Undefined Behavior:
C11 Standard - 7.21.6.1 The fprintf
function(p9) "If
a conversion specification is invalid, the behavior is undefined. If
any argument is not the correct type for the corresponding conversion
specification, the behavior is undefined."
More likely than not what will print is the actual pointer address on system where pointers are the same size as int (e.g. x86), otherwise, you will print 4-bytes out of the 8-byte pointer if you are lucky.
The size of a typical integer is 4 bytes(range of integers being -2,147,483,648 to 2,147,483,647) for modern compilers.
And when "%d" is used as a type specifier, it prints the address pointed by ptr as a 32-bit integer.
But
Since the size of ptr is typically 8 bytes the value of address that is in Hexadecimal can't be converted to Decimal completely,
Thus an inconsistency is introduced.
Understand it another way:
140723910431936 is nowhere between the range of integers and printing it with type specifier "%d" won't provide correct result

Why does %d,and %p give different values? [duplicate]

This question already has answers here:
What happens when I use the wrong format specifier?
(2 answers)
Correct format specifier to print pointer or address?
(5 answers)
Closed 4 years ago.
As you can see in the program, The first output is 6356744 and the second output is 0060FF08, why is it different? Is the %d typecasting it into an integer, if so, how?
#include<stdio.h>
int main()
{
int *a;
int b = 7;
a = &b;
printf(" The value of a = %d",a);
printf("\n The value of a= %p",a);
}
Printing a pointer with %d is formally undefined behavior, meaning anything can happen, including a program crash. Your program will for example likely break when you compile it as a 64 bit application, where int is 32 bits but a pointer is likely 64 bits. Therefore, always use %p and never anything else when printing a pointer.
There is no implicit conversion taking place - the printf family of functions doesn't have that kind of intelligence - it doesn't know the type passed. With the format specifier, you tell the function which type it is getting. And if you lie to printf and say "I'll give you an int" and then give it a pointer, you unleash bugs. This makes the printf family of functions very dangerous in general.
(The only implicit conversion that take place in printf is when you pass small integer types or float, in which case the "default argument promotions" take place and promote the parameter either to int or double. This is not the case here, however.)
In this specific case, you happened to get the decimal representation of 0x0060FF08, which is by no means guaranteed.
Pedantically, you should also cast the pointer to type (void*) since this is what %p expects.
%p prints a pointer and it's not necessarily hexadecimal, or even a number
If format specifiers do not match the datatype of the provided parameter, you yield undefined behaviour. %d expects an integral value, such that when you pass a pointer value, you get undefined behaviour (cf., for example, cppreference.com-printf):
...If any argument after default argument promotions is not the type
expected by the corresponding conversion specifier, or if there are
fewer arguments than required by format, the behavior is undefined.
The (only) correct format specifier for printing pointer values is %p, usually printing the address in hex format.
One of the undefined behaviours is that %d takes the pointer value as an 32/64 bit integral value and hence prints decimals, which - if you printed it using the correct %p-format - corresponds to the hex-value of the address (yet in decimal format).
%d prints an int, in decimal.
%p prints a pointer (strictly speaking, a void * pointer) in an implementation-defined way, typically in hexadecimal.
On a machine where ints and pointers have different sizes, trying to print a pointer using %d will typically give a meaningless result. For example, on a lot of machines these days, ints are 32 bits while pointers are 64 bits. So if you try to print a pointer using %d, what you might get is half the pointer value, in decimal.
(Strictly speaking, trying to print a pointer using %d is undefined, no matter what the relative sizes are.)
Bottom line, use the right printf specifier for the job. Use %d to print ints. Use %p to print pointers. Don't try to mix 'n' match.

How can a variable have two different addresses at same point of time? [duplicate]

This question already has answers here:
How to printf a memory address in C
(2 answers)
Closed 5 years ago.
I tried to play around a little bit with pointer for some assigned value of 'i' and what I found out in in that there are two different addresses assigned for declaration %u and %lu,%llu. How is possible that a variable can have two different addresses at the same instance of execution -
#include <stdio.h>
int main(void)
{
int i;
float f;
printf("\nEnter an integer:\t");
scanf("%d",&i);
printf("\nValue of address of i=%u",&i);
printf("\nvalue of address of i=%d",&i);
printf("\nValue of address of i=%lu",&i);
printf("\nValue of address of i=%llu",&i);
printf("\nvalue of i=%d",i);
printf("\nvalue of i=%u",i);
printf("\nvalue of i=%lu",i);
printf("\nvalue of i=%llu\n",i);
}
This is the output -
aalpanigrahi#aalpanigrahi-HP-Pavilion-g4-Notebook-PC:~/Desktop/Daily programs/pointers$ ./pointer001
Enter an integer: 12
Value of address of i=1193639268
value of address of i=1193639268
Value of address of i=140725797092708
Value of address of i=140725797092708
value of i=12
value of i=12
value of i=12
value of i=12
Here we can clearly see that for %u and %d the address is 1193639268 (Though the output of %d and %u might not be equal in all cases) and the output of %lu and %llu is 140725797092708 and what is it's physical significance.
The proper format specifier for printing a pointer is %p.
Using the wrong format specifier, such as %d, %u, %lu, or %llu invokes undefined behavior.
As the the specific behavior you're seeing, a pointer on your particular implementation is probably an 8 byte value, while an int or unsigned int is probably a 4 byte value. As a result, using %d or %u only reads the first 4 bytes of the 8 byte value passed in to the function and prints that value. When you then use %lu or %llu, all 8 bytes are read and printed as such.
Again, because you're invoking undefined behavior, you can't depend on this particular output to be consistent. For example, compiling in 32-bit mode vs 64-bit mode will likely give different results. Best to use %p, and also to cast the pointer to void *, as that is the specific pointer type expected by %p.
There is only one address. You're using integer printing codes of varying widths, so sometimes you see 32 bits of address, and sometimes you see 64 bits of address. How much is valid depends on your system; on a 32 bit system, printing 64 bits means 32 bits of the value are garbage; on a 64 bit system, printing 32 bits means you're omitting half the pointer.
There is a dedicated format code, %p that's intended for printing pointers, use that, not integer printing codes.
You're using the wrong format specifier, which results in undefined behavior. In this specific case the behavior is that 1193639268 (0x47257D64) is the lower part of 140725797092708 (0x7FFD47257D64)
The correct format specifier for addresses is %p
It doesn't. It's just that you are using incorrect format specifiers for pointer types.
The behaviour on doing that is undefined. The output you observe is a manifestation of that undefined behaviour.
Use %p for a pointer, and cast the pointer argument to a const void* type (many compilers are lax on this last point but it's good practice nonetheless).

What is printing out when int pointer is printed with %d?

This code:
#include <stdio.h>
int main() {
int num;
int *pi;
num = 0;
pi = &num;
printf("address: %p | %d\nvalue: %d\n", pi, pi, *pi);
}
produces this output:
address: 0x7fff5952f9cc | 1498610124
value: 0
I know that the left one is supposed to be the correct address, but what is printing out next to the address?
%p tells printf to treat the corresponding variable as a pointer, thus printf prints p as a pointer; that is, a hexadecimal representation (i.e. 0x7fff5952f9cc). %d on the other hand tells printf to treat the corresponding variable as numeric. Therefore, what is being printed is the actual, numeric value of p (i.e. 1498610124) which is just 0x5952f9cc in base 10.
Now, the reason why these two representations of the same variable seem to have different values is that %d only tells printf to expect a number---it doesn't specify that number's type. If you cast 0x7fff5952f9cc (a 64-bit integer) to int (a 32-bit type) you get 1498610124 (notice 0x7fff getting dropped).
You are printing the address in decimal instead of in hex but it is truncated to an int.
I guess you are executing this program on a 64bit machine.
The number printed next to the address is still the address of the pointer printed in the integer format. You can also see that the value is truncated
decimal of 0x7fff5952f9cc = 140734691998156. but it is printed as 1498610124 which is due to truncation.
you are trying to print the address of num in hex and decimal value respectively. If I am not wrong you are running your program on a 64 bit architecture and hence the address will be of 8 bytes. So your address fits in long data type. By giving %d you are value is getting truncated here. Instead of %d please use %ld. So your printf of statement should be actually as below
printf("address: %p | %ld\nvalue: %d\n", pi, pi, *pi);
Now run the program you will get your value correctly in decimal format.
It could be anything, because it's Undefined Behaviour. (C standard, § 7.21.6.1, The fprintf function):
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
You print pi (a pointer to an int) with two format specifiers, %p and %d. According to the C standard (and probably reproduced word for word in man fprintf on your system):
d,i The int argument is converted to signed decimal in the style [−]dddd
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 neither of those uses is correct. It's not a pointer to void and it's also not an int. So what you should write is:
printf("address: %p | %d\nvalue: %d\n", (void*)pi, (int)pi, *pi);
On your system, that probably produces the same output (Undefined Behaviour includes unexpectedly producing the incorrectly expected behaviour) but it might not. In any case, writing the line correctly makes it relatively clear what the second number printed is: it's the value of the pointer converted to an integer.
However, there is no guarantee that this will work, either. Again, from the standard (§6.3.2.3, Pointers, para. 6):
Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined.
(The "previously specified" case is that a NULL pointer may reliably be converted to any integer type; it will have the value 0.)
So the idea is that a pointer is a lot like an integer, but it might be the size of a long. Or a long long. Or something else. It might even be bigger than any integer type, but if there is some integer type which is the right size and you #include <stdint.h>, that integer type will be typedef'd to intptr_t and its unsigned version (probably more useful) will be uintptr_t. Unfortunately, there is no standard printf conversions for those sizes, so if you really want to, you would need to #include <intypes.h> and write:
printf("address: %p | %" PRIuPTR "\nvalue: %d\n",
(void*)pi, (uintptr_t)pi, *pi);
Alternatively, because it is always allowed to convert any integer to any unsigned integer (with possible loss of information, but with a well-defined conversion), you could use two casts:
printf("address: %p | %u\nvalue: %d\n",
(void*)pi, (unsigned)(uintptr_t)pi, *pi);
(Because that supplies an unsigned int argument, the format specifier must be u instead of d.)
When using printf, the "p" modifier is intended to print out a memory address in hex format. The "d" modifier tells it to cast the value to a signed integer value. So it's taking 0x7fff5952f9cc and turning it into a signed int.
See this for more details on printf.
In that code who have to print the address as the %d so during compile time it displayed warning and %p display the hexadecimal but %d display the integer.
Its lower part – 4 least significant bytes – of the pointer value in decimal:
0x5952F9CC == 1498610124.

Resources