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

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

Related

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

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.

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.

Storage of variables and dereferencing them

Based on the following snippet in C
int c1,c2;
printf("%d ",&c1-&c2);
Output : -1
Why does this code not return a warning saying the format %d expects of type int but it's getting a (void *) instead.
Why does it return -1 as an answer(and not 1)? Even if it's subtracting addresses it should be -4 and not -1. When I change the printf statement to printf("%d ",&c2 - &c1) I get 1 and not any random value! Why?
If I change the printf statement as printf("%d ",(int)&c1 - (int)&c2) am I typecasting an address to an integer value? Does that mean the value of the address stored as hexadecimal is now converted to int and then subtracted?
1) It's getting an int. Pointer-to-something minus pointer-to-something is an integer value (type ptrdiff_t). It tells you how many elements away are two pointers pointing into the same array.
2) As the two pointer do not point into the same array, the difference is undefined. Any value can be obtained.
3) Yes. But the "hexadecimal" part is incorrect. Addresses are stored in bits/binary (as are integers). What changes is the interpretation by your program. This is independent of the representation (hex/dec/oct/...).
There are multiple cases of undefined behavior here.
If we go to the draft C99 standard section 6.5.6 Additive operators it says (emphasis mine):
When two pointers are subtracted, both shall point to elements of the
same array object, or one past the last element of the array object;
the result is the difference of the subscripts of the two array
elements. The size of the result is implementation-defined, and its
type (a signed integer type) is ptrdiff_t defined in the
header. If the result is not representable in an object of that type,
the behavior is undefined.
Although, what you have is undefined behavior since the pointers do not point to elements of the same array.
The correct format specifier when using printf for ptrdiff_t would be %td which gives us a second case of undefined behavior since you are specifying the incorrect format specifier.
1) A void* is nothing but an adress. An adress is an number (a long). There, the adress is implicitly cast to an int.
2) In memory, your variable aren't store in the same order than in
your code ;). Furthemore, for the same reason :
int a[2];
a[0] = 3;
*(a + 1) = 5; // same that "a[1] = 5;"
This code will put a "5" in the second case. Cause it will actually do :
*(a + 1 *sizeof(*a)) = 5;
3) Hexadecimal is a number representation. It can be store in a int ! Example :
int a = 0xFF;
printf("%d\n", a); // print 255
I hope that i have answered your questions.
1) Some compilers do issue warnings for malformed printf arguments, but as a variadic function, the run-time has no way of checking that the arguments are of the type specified by the format string. Any mismatch will issue undefined behaviour as the function attempts to cast such an argument to an incorrect type.
2) You say the result should be -4 but that's not correct. Only arrays are guaranteed to have their pointers aligned contiguously. You cannot assume that c2 is at (&c1 + 1).
3) (int)&c1 is converting the address of c1 to an int. That's again, in general, undefined behaviour since you don't know that int is big enough to hold the pointer address value. (int might be 32 bits on a 64 bit chipset). You should use intptr_t in place of the int.

Resources