I casted the memory address from double to an integer .
Even though they point to the same address why the values are different ?
#include<iostream>
using namespace std;
int main()
{
double d = 2.5;
auto p = (int*)&d;
auto q = &d;
cout<<p<<endl; // prints memory address 0x7fff5fbff660
cout<<q<<endl; // print memory address 0x7fff5fbff660
cout<<*p<<endl; //prints 0
cout<<*q<<endl; // prints 2.5
return 0;
}
But why the value are different
0x7fff5fbff660
0x7fff5fbff660
0
2.5
Program ended with exit code: 0
Suppose you have "11" written on a piece of paper. That is eleven if it's decimal digits. That is two if there's one mark for each value. That's three if it's binary. How you interpret stored information affects the value you understand it to be storing.
double d = 2.5;
auto p = (int*)&d;
auto q = &d;
p and q are created pointing to the same memory location. The memory holds a double (usually 8 bytes)
When you create
auto p = (int*)&d;
you are telling the compiler ( reintepret_cast< int*> ( &d) ) that the value in d was an integer.
So the values of the pointers are the same, but the types are not.
When you print out
cout<<*q<<endl; // prints 2.5
You are displaying the correct value - as it came in and out through that.
when you print out
cout<<*p<<endl; //prints 0
You are looking at 4 (typically) bytes of the 8 byte memory, and interpreting them as an integer.
These happen to be 0x00, 0x00, 0x00, 0x00
It's because you've violated the strict aliasing rule, giving you undefined behavior. You cannot acesss type A through a pointer of type B and just pretend it works.
TL;DR:
if you have an int* pointing to some memory containing an int and then
you point a float* to that memory and use it as a float you break the
rule. If your code does not respect this, then the compiler's
optimizer will most likely break your code.
The memory addresses are the same, and they both point to a double-precision floating point number in memory. However, you've asked the compiler to treat one as an integer and another as a double. (A pointer might just be a memory address, but at compile-time the compiler has information about the type as well.) It just so happens that the in-memory representation of this particular double-precision number looks like a 0 when treated as an integer.
Because you have casted them to different types yourself.
When you do auto p = (int*)&d; you are asking the compiler to store a double value in a memory area allocated for an integer. An integer and a double are represented in different formats in a computer's memory. A double is stored using a floating point representation in memory, while an int is not. This is a classic example of undefined behaviour.
Related
We know integer variable take 4-byte memory address. I just wonder, if we initialize integer variables and make a pointer to it. I can get the value of it from the pointer (which have the address of the variable: 0x22fef8 in my computer). But how about the memory address after 0x22fef8 which is 0x22fef9, 0x22fefa, 0x22fefb? What is in there? Are we will get the value of the variable if we dereference this address? How to access them?
You're right: in a 32-bit computer an integer takes up four bytes. In C, that can be expressed by the following code:
int i = 0x12345678;
int *p_i = &i;`
If p_i gets the value 0x22fef8, then p_i++ would become 0x22fefc since it would point to the next integer. If you want to see what's in the bytes that make up i, you need to use a different pointer:
typedef uint_8 byte;
byte *p_b = (byte *)&i;`
That means that you change the pointer-to-int that &i represents and typecast it to be a pointer-to-byte. It will still have the value 0x22fef8 since that's where the first byte of i is - but now if you do a p_b++ it will change to 0x22fef9. And note that if you print out the original value of *p_b (that is, the byte that it is pointing to), it will not give the same value as i. Depending on the computer, it will print out either the first byte or the last byte: 0x12 or 0x78, or at least the decimal versions thereof.
This is due to the "endianness" of the computer, which affects the storage of multi-byte values. Little-endian computers like the x86 store the littlest part of the value first - the 0x78 - while Power PC computers store the biggest part of the value first - the 0x12.
int types take up four bytes on your system, so those are all occupied by the int. All are inaccessible except the first one.
It is to note some ints take up two bytes on other systems. It isn't regulated by the standard.
If you want to see the values in those addresses, just do this and you will get values of next 10 addresses
int main()
{
int a = 5;
int *p_i = &a; // The address of 'a' is stored in pointer 'p_i'
// Now you want to check the values in 10 further addresses
for ( int i = 0; i < 10; i++ )
{
int value = *p_i; // Here it is getting the address of pointer as integer value
cout << value << endl;
p_i++;
}
return 0;
}
If size of the union allocated in memory is equal to the biggest data type member in bytes then could anyone tell me how compiler is storing and fetching two datas double d and int i (total 8+4 bytes) (double on my machine is of 8 bytes) .
#include<stdio.h>
union test {
int i;
double d;
};
int main()
{
union test obj;
obj.d=15.5;
obj.i=200;
printf("\nValue stored in d is %f",obj.d);
printf("\nValue stored in i is %d",obj.i);
printf("\n size of obj is %d ",sizeof(obj));
}
**Output is : Value stored in d is 15.500000
Value stored in i is 200
size of obj is 8**
The way it can store both is "pure luck". I'm just going to assume your computer architecture uses IEEE 754 floating point numbers and try to explain what you're seeing. Your union really does use only eight bytes, but 15.5 looks like this in hex: 402F000000000000. As you can see the lower four bytes are completely zero. Now let's set the lowest four bytes to an integer 200 and see what happens to the eight byte value. That gives us 402F0000000000C8. Now say you read all eight bytes back as a double now, in IEEE754 you get 15.500000000000355 which when printed will round off to 15.5 making it appear that the union can store both a double and an int.
All that said accessing both members of the union like that is undefined behavior in C++ at least up to C++11 (even though it behaves in the logical way on all platforms I'm aware of), so this is simply one possible explanation for the behavior you observe. In C it appears to be completely legal though.
The reason it seems like you can store both numbers in overlapping memory is the way the representation of the small values you chose is arranged.
If you try values that require more information stored like for example:
obj.d=100000000000000;
obj.i=0xffffffff;
You'll see a difference in the output of printing the double value:
Value stored in d is 100000059097087.984375
I think it's not really working the way you think it is. If you add a bit more to the test:
#include<stdio.h>
union test {
int i;
double d;
};
int main()
{
union test obj;
obj.d=15.5;
obj.i=200;
printf("\nValue stored in d is %f",obj.d);
printf("\nValue stored in i is %d",obj.i);
printf("\n size of obj is %d ",sizeof(obj));
obj.d=17.5;
printf("\nValue stored in d is %f",obj.d);
printf("\nValue stored in i is %d",obj.i);
printf("\n size of obj is %d ",sizeof(obj));
obj.i=300;
printf("\nValue stored in d is %f",obj.d);
printf("\nValue stored in i is %d",obj.i);
printf("\n size of obj is %d ",sizeof(obj));
}
Output is:
$ ./main
Value stored in d is 15.500000
Value stored in i is 200
size of obj is 8
Value stored in d is 17.500000
Value stored in i is 0
size of obj is 8
Value stored in d is 17.500000
Value stored in i is 300
size of obj is 8
Note that value of i is 0 in the middle there! That's because it got (partially?) overwritten.
If I understand correctly it's undefined behavior there, and exactly what value you see will depend on the architecture you compile it for, the alignment the compiler uses for this structure etc. etc.
Edit:
I think I understand the original question now -- it's about, why is it possible to recover the first stored value at all, right? Why don't I see gibberish instead of 200.
My guess is that it might depend on some implementation details of the floating point stuff? Maybe the double happens not to overwrite the bits of "int" if its a "simple" double like 17.5. Not completely sure. Edit: See "imreal"'s answer.
You can store either i or d to your union, not both at the same time. The statement
obj.i=200;
overwrites the value stored at the memory allocated for the union. Now accessing obj.d with %f specifier will invoke undefined behavior that's because the value stored in obj is int.
After writing to obj.i, reading from obj.d is undefined behavior, and as far as the C standard is concerned anything can happen.
In this particular case you probably don't see anything happen because of floating point numbers are laid out in memory. You are changing some of the least significant bits of the mantissa, creating a change that's not seen in the first 6 decimal digits. Add more digits:
printf("\nValue stored in d is %.17f",obj.d);
and you'll get:
Value stored in d is 15.50000000000035705
If I declare
int x = 5 ;
int* p = &x;
unsigned int y = 10 ;
cout << p+y ;
Is this a valid thing to do in C++, and if not, why?
It has no practical use, but is it possible?
The math is valid; the resulting pointer isn't.
When you say ptr + i (where ptr is an int*), that evaluates to the address of an int that's i * sizeof(int) bytes past ptr. In this case, since your pointer points to a single int rather than an array of them, you have no idea (and C++ doesn't say) what's at p+10.
If, however, you had something like
int ii[20] = { 0 };
int *p = ii;
unsigned int y = 10;
cout << p + y;
Then you'd have a pointer you could actually use, because it still points to some location within the array it originally pointed into.
What you are doing in your code snippet is not converting unsigned int to pointer. Instead you are incrementing a pointer by an integer offset, which is a perfectly valid thing to do. When you access the index of an array, you basically take the pointer to the first element and increase it by the integer index value. The result of this operation is another pointer.
If p is a pointer/array, the following two lines are equivalent and valid (supposing the pointed-to-array is large enough)
p[5] = 1;
*(p + 5) = 1;
To convert unsigned int to pointer, you must use a cast
unsigned int i = 5;
char *p = reinterpret_cast<char *>(i);
However this is dangerous. How do you know 5 is a valid address?
A pointer is represented in memory as an unsigned integer type, the address. You CAN store a pointer in an integer. However you must be careful that the integer data type is large enough to hold all the bits in a pointer. If unsigned int is 32-bits and pointers are 64-bits, some of the address information will be lost.
C++11 introduces a new type uintptr_t which is guaranteed to be big enough to hold a pointer. Thus it is safe to cast a pointer to uintptr_t and back again.
It is very rare (should be never in run-of-the-mill programming) that you need to store pointers in integers.
However, modifying pointers by integer offsets is totally valid and common.
Is this a valid thing to do in c++, and if not why?
Yes. cout << p+y; is valid as you can see trying to compile it. Actually p+y is so valid that *(p+y) can be translated to p[y] which is used in C-style arrays (not that I'm suggesting its use in C++).
Valid doesn't mean it actually make sense or that the resulting pointer is valid. Since p points to an int the resulting pointer will be an offset of sizeof(int) * 10 from the location of x. And you are not certain about what's in there.
A variable of type int is a variable capable of containing an integer value. A variable of type int* is a pointer to a variable copable of containing an integer value.
Every pointer type has the same size and contains the same stuff: A memory address, which the size is 4 bytes for 32-bit arquitectures and 8 bytes for 64-bit arquitectures. What distinguish them is the type of the variable they are poiting to.
Pointers are useful to address buffers and structures allocated dynamically at run time or any sort of variable that is to be used but is stored somewhere else and you have to tell where.
Arithmetic operations with pointers are possible, but they won't do what you think. For instance, summing + 1 to a pointer of type int will increase its value by sizeof(int), not by literally 1, because its a pointer, and the logic here is that you want the next object of this array.
For instance:
int a[] = { 10, 20, 30, 40 };
int *b = a;
printf("%d\n", *b);
b = b + 1;
printf("%d\n", *b);
It will output:
10
20
Because b is pointing to the integer value 10, and when you sum 1 to it, or any variable containing an integer, its then poiting to the next value, 20.
If you want to perform operations with the variable stored at b, you can use:
*b = *b + 3;
Now b is the same pointer, the address has not changed. But the array 10, 20, 30, 40 now contains the values 13, 20, 30, 40, because you increased the element b was poiting to by 3.
How come you can assign an address to an integer variable like this,the complier will not give an error. i always though you can only assign integer values to a integer variable
int a=0x28ff1c
You can do the same for a char variable, the complier will not give a error
char b=0x28ff1c
It will output on the console screen rubbish value for char b and a random value for int a
cout<<b
<<endl;
cout<<a;
Can someone explain to me why there is a difference in the output for char b and int a.
Can someone aslo explain to me why a char variable and integer variable can have addresses assign to it
0x28ff1c is not an address itself - it's just a hexadecimal number.
The following are equivalent:
int a = 2686748; //decimal number
int a = 0x28ff1c; //hexadecimal number
int a = 012177434; //octal number
An address is represented by a pointer - if it's just that, an address, you can use a void*:
void* p = (void*)0x28ff1c;
In which case
int a = p;
wouldn't compile. p is an address, the number itself isn't.
The number 0x28ff1c is just the hexadecimal (base-16) representation of the decimal (base-10) number 2686748. As cout defaults to printing decimal values for integers, that is probably the number you got printed.
The case with char b = 0x28ff1c is slightly different, because
char is not large enough to hold that value. The practical result is that it gets truncated to 0x1c.
cout treats char specially, because it is normally used to hold textual data, so cout prints the character that has the code 0x1c, which is some kind of control character. You could try it with 0x41 for example (which represents 'A' in ASCII and UTF-8).
And note that there is nothing that marks 0x28ff1c as being an address. An address would be formed by &a or (void*)0x28ff1c.
Because in any literal starting 0x is actually an integer. So it is allowed. An address is can sometimes be an integer.
You can also use *(int *)(Address) = value as a construct to assigne a value to Address and use the answer by #Luchian Grigore
float b = 1.0f;
int i = b;
int& j = (int&)i;
cout<<j<<endl;
o/p = 1
But for the following scenario
float b = 1.0f;
int i = b;
int& j = (int&)b;
cout<<j<<endl;
O/P = 1065353216
since both are having the same value it shall show the same result ...Can anyone please let me know whats really happening when i am doing some change in line number 3 ?
In the first one, you are doing everything fine. The compiler is able to convert float b to int i, losing precision, but it's fine. Now, take a look at my debugger window during the execution of your second example:
Sorry for my Russian IDE interface, the first column is variable name, the second is value, and the third is type.
As you can see, now the float is simply interpreted as int. So the leading 1 bits are interpreted as the integer's bits, which leads to the result you are getting. So basically, you take the float's binary representation (usually it's represented as sign bit, mantissa and exponent), and try to interpret it as an int.
In the first case you're initializing j correctly and the cast is superfluous. In the second case you're doing it wrong (i.e. to an object of a different type) but the cast shuts the compiler up.
In this second case, what you get is probably the internal representation of 1.0 interpreted as in integer.
Integer 1 and floating-point 1.0f may be mathematically the same value, but in C++ they have different types, with different representations.
Casting an lvalue to a reference is equivalent to reinterpret_cast; it says "look at whatever is in this memory location, and interpret those bytes as an int".
In the first case, the memory contains an int, so interpreting those bytes as an int gives expected value.
In the second case, the memory contains a float, so you see the bytes (or perhaps just some of them, or perhaps some extra ones too, if sizeof(int) != sizeof(float)) that represent the floating-point number, reinterpreted as an integer.
Your computer probably uses 32-bit int and 32-bit IEEE float representations. The float value 1.0f has a sign bit of zero, an exponent of zero (represented by the 8-bit value 127, or 01111111 in binary), and a mantissa of 1 (represented by the 23-bit value zero), so the 32-bit pattern would look like:
00111111 10000000 00000000 00000000
When reinterpreted as an integer, this gives the hex value 0x3f800000, which is 1065353216 in decimal.
Reference doesn't do any memory allocation, it just places an entry into table of local names and their addresses. In first case name 'j' points to the memory previously allocated to int datatype (for variable 'i'), while in second case name 'j' points to memory allocated to float datatype (for variable 'b'). When you use 'j' compiler interprets data at the appropriate address as if it was int, but in fact some float is placed there, that's why you get some "strange" numbers instead of 1
The first one first casts b to an int before assigning it to i. This is the "proper" way, as the compiler will properly convert the value.
The second one does no casting and re-interpret's b's bits as an integer. If you read up on floating point format you can see exactly why you're getting the value you're getting.
Under the covers, all your variables are just collections of bits. How you interpret those bits changes the perceived value they represent. In the first one, you're rearranging the bit pattern to preserve the "perceived" value (of 1). In the second one, you're not rearranging the bit pattern, and so the perceived value is not properly converted.