I have such code:
double x = 100.1;
double y;
int *p;
p = (int *) &x;
y = *p;
cout << "y value is: " << y << endl;
I understand that it's wrong and we get 4 bytes instead of our 8 bytes. I also know floating numbers have some tricky representation at memory (but don't know how), but this script gives me such output:
y value is: 1.71799e+09
As I understand it's also value with floating point. By my pointer is int and I also expect int result. Why it's not? What I should read to understand?
By my pointer is int and I also expect int result. Why it's not?
Because y is a double, not an int. Now, if you mean to ask why doesn't y have an integral value, since it should be the result of the conversion of an int (which must* have an integral value) to double, take a look at the output of the following:
std::cout << "y value is: " << std::fixed << y << '\n';
The output you should see is:
y value is: 1717986918.000000
So, y does have an integral value, you simply printed it out using scientific notation. And if you wonder why y has this particular integral value, it's because that's the value *p had.
std::cout << "*p is: " << *p << '\n';
*p is: 1717986918
If you were to look at a memory dump of x with the value of 100.1, you would see:
66 66 66 66 66 06 59 40
And when you access this as an int, you get 66 66 66 66, which, converted to decimal, is 1717986918.
One other thing to note is that none of this is guaranteed by C++. In fact your program is not actually legal, because you're violating the aliasing rules when you access the double x through a pointer to int. Your program could be made legal and get the same results, but C++ doesn't specify the representation of floating point values, so the particular integral value could legally be different.
What I should read to understand?
Here's an article that plays with the representation of floats: http://ridiculousfish.com/blog/posts/float.html
C++ doesn't specify how floats are represented, but most C++ implementations use IEEE-754, so you might also take a look at that specification. Here's the wikipedia page to start you on that: https://en.wikipedia.org/wiki/IEEE_floating_point
To learn about C++'s aliasing rules you can find and read the spec. strict aliasing is covered in ยง3.10/10, IIRC. There are also plenty of questions and answers about aliasing here on SO.
1.71799e+09 is the floating point representation of the integer 1,717,99x,xxx.
By my pointer is int and I also expect int result. Why it's not?
Your pointer is int *, and you are getting an int result.
But that's not what you're displaying. You're displaying y which is a double.
1.71799e+09 is the double representation of the int you got.
When you do
y = *p;
The variable y takes the int pointed to by p, and then converts it to a double.
Suppose sizeof(double) is 8 and sizeof(int) is 4
Doing x = 100; you put the double value 100 in x on 8 bytes. Then when you do y = *p; you would only use 4 of the 8 bytes, as an int value, then convert that number to a double.
The binary format of a double and of an int are different. E.g. 100 as double is not represented the same way as 100 int (let alone the size difference, e.g. 8 vs 4).
See this link
double x = 100.1;
double y;
int *p;
p = (int *) &x;
// Set a pointer of type integer to point at a floating point. Better C++ style
// would be p = reinterpret_cast<int *>(&x);
// which explains more clearly what you are doing - reinterpreting the pointer as
// a different type.
y = *p;
// *p is an integer. So y is set to the value of *p, which is some crazy
// integer value formed from the interpretation of a double as integer.
cout << "y value is: " << y << endl;
See comments in the code above. You are making a pointer point to data of a different type, then wondering why the binary digits transformed don't represent what it originally represented...
(Technically, this code is in violation of the rules about aliasing - basically, you are using the same piece of memory for two different purposes, and the compiler is not obliged to "do the right thing" in this case - I suspect it does something of what you can expect in this particular case - if what you expect is that you get an integer value represented by the four first bytes of a double, that is).
If you want y to actually contain the integer representation of the number in x, you want:
y = (int)x;
There is no sensible way we can use a pointer to do this conversion.
You're triggering undefined behavoir when you run the following line:
p = (int *) &x;
Once you've triggered undefined behavoir the rest of your question is fairly pointless as reasoning about undefined behavoir doesn't make sense (although looking at the rest of your question, it may be that this bit of undefined behavoir doesn't affect what you're really asking. I'm not sure though.)
Read C++ pointers and data types documentation
http://www.cplusplus.com/doc/tutorial/pointers/
http://www.cplusplus.com/doc/tutorial/variables/
Related
If I have:
#include <iostream>
int main()
{
float a,b,c;
b = 7;
c = 2;
a = (int) (b / c);
std::cout << a;
}
Does (int) only affect the data type during cout so that 'a' can be printed as an integer or does it affect 'a' as a variable changing it to an 'int'?
Does (int) only affect the data type during cout so that a can be printed as an integer or does it affect a as a variable changing it to an int?
Neither.
a = (int)(....);
only changes what is assigned to a. In this case it truncates the floating point number and assigns the integral part of the number to a.
It does not change how a is processed in cout << a. You will notice a truncated value in the output. However, the reason for that is that a truncated value got assigned to a in the previous statement not because cout << a is processed differently.
It does not change the type of a to an int. The type of a variable cannot be changed in C++. It remains unchanged for the entire life of the program.
In this particular case it converts from a float value, the result of b/c into an int, then as a is still a float, converts it back to a float.
This is an easy, if sometimes problematic way of rounding something to an integer value.
Remember that in C++ variables never change their fundamental type. Something defined as a float stays a float forever. You can force other values into the same memory location, you can recast them, but the variable itself always has a fixed intrinsic type.
Cast does not change the type of a variable the casted value is assigned to.
In your case, result of b/c is casted (truncated) to an int, which is then promoted to float.
In this case the int is a cast datatype.
What the computer are thinking
Inside the main function:
float a, b, c;
Declaring 3 variables of data_Type float.
b = 7;
c = 5;
Assigned value of 7 to b and value 5 to c.
a = (int) (b / c);
A is equal to b/c ==> 7/5 ==> 1.4, wait, the programmer asked to cast the data as int so 1.4 ==> 1
std::cout << a;
Output: 1.0
Hope this help
When I want to calculate the address of a function, I do the following:
HMODULE base = GetModuleHandle(L"program.exe"); // Module base addr
// Adding an offset to the base
std::cout << (base + 0x8F0A0) << std::endl; -> Wrong!
I'm not sure why the result is wrong. I've tested it via online hex calcs and also have debugger to check both values.
Could base be considered decimal and other being hex, produce wrong results?
How can I get a result in hex?
As explained here, depending on whether STRICT is defined, HMODULE is essentially either a void* or a <unique type>*, the purpose of this being to make each handle type a different C++ type, meaning compiler errors when you mix and match. In the former case, pointer arithmetic won't compile. In the latter case, it will compile, but you can't rely on anything happening because pointer arithmetic takes the type's size into account and because pointer arithmetic is undefined if you leave the object/array being pointed to.
You should treat this pointer as pointing to nothing in particular, and therefore not do pointer arithmetic. You have to reinterpret_cast it to an integral type that you're sure is large enough (std::uintptr_t) and then do arithmetic on that integral value.
In my local header, this unique type contains an int member, so adding 1 will actually move the pointer ahead by 4 bytes (you know, except for the undefined behaviour and all). It just so happens that 0x00DE0000 + 4 * 0x8F0A0 is your 0x0101C280 value.
You're problem lies with the value GetModuleHandle(L"program.exe") returning: 00DE0000. You need to utilise C hexadecimal syntax, so you need to add and precede "0x" to your hex number 00DE0000.
Hence, your base number should be casted to a numeric value: 0x00DE0000
0x00DE0000 is equal to 00DE0000
Try using std::string to_string(int value); to convert it to string, then convert your hex values (base) to C hexadecimal syntax (add "0x" at the beginning of your hex value). To finish off, convert your base value back to a numeric value (e.g. use std::stoi) and perform the addition using std::hex.
Try this code here.
#include <iostream>
int main () {
int hex1 = 0x8F0A0;
int hex2 = 0x00DE0000; // Using int values
std::cout << std::hex << hex1 + hex2 << std::endl;
}
As Chris has said, I had the same case, solving the thing like this:
int offset = 0x8F0A0;
std::uintptr_t base = reinterpret_cast<uintptr_t>(GetModuleHandle(L"program.exe"));
// Here added 4 bytes to the offset.
std::cout << std::hex << (base + (offset + 4096)) << std::endl;
I have the followig code and I want to know why I have the following output:
#include <iostream>
int main() {
double nValue = 5;
void *pVoid = &nValue;
short *pInt = static_cast<short*>(pVoid);
std::cout << *pInt << std::endl;
return 0;
}
And it outputs me '0'. I want to know why is this happening. Thank you!
You have UB (Undefined Behaviour), as you're violating pointer aliasing rules. This means anything can happen.
For example, the compiler has all rights to expect a short* will never refer to a double object, so it can pretty much interpret *pInt however it wants.
Or it's possible that the compiler interprets the code literally, and it just so happens that on your platform, the binary representation of 5.0 starts with two (or sizeof(short)) bytes of zeroes.
You are casting memory block with double data to short. Since you store a small value in that block it is not stored in first bits. Thus first bits are zero. But it rely on internal double representation and short size, so it is not guaranteed to be the same on different platforms
You're trying to interpret the contents of a double as a short. This invokes undefined behavior - your program is free to do anything.
pVoid points to a bit pattern that represents a double. The type information is lost for the compiler once you use a void*. When casting the void* to short*, you claim that that the bit pattern pointed to is a short, which it isn't. The representation of a short and a double in memory are completely different. When you dereference pInt, the memory at that location happens to be 0. The compiler no longer knows at this point that the value's type is really double, so no implicit conversion is possible, if that's what you were expecting.
Just for fun, most probably the double representation of 5 on your machine is this
*double = (5)
0000000000000000000000000000000000000000000000000000000000000101
^^^^^^^^^^^^^^^^
*short = (0)
This should show you why this is happeneing
int main() {
double nValue = 5;
short nValue_short = 5;
std::bitset<sizeof(double)*8> bit_double(nValue);
std::bitset<sizeof(short)*8> bit_short(nValue_short);
std::cout << bit_double << std::endl;
std::cout << bit_short << std::endl;
return 0;
}
i run this code in c++:
#include <iostream>
using namespace std;
int main()
{
float f = 7.0;
short s = *(short *)&f;
cout << sizeof(float) << endl
<< sizeof(short) << endl
<< s << endl;
return 0;
}
i get the following out pot:
4
2
0
but, in a lecture given in Stanford university, Professor Jerry Cain says he is sure the out pot well not be 0.
the lecture is can be fond here. he says that around the 48 minute.
is he wrong, or that some standard change since? or is there a difference between platforms?
I'm using g++ to compile my code.
EDIT: in the next lecture he does mention "big endian" and "small endian" and says that they well affect the result.
static void bitPrint(float f)
{
assert(sizeof(int) == sizeof(float));
int *data = reinterpret_cast<int*>(&f);
for (int i = 0; i < sizeof(int) * 8; ++i)
{
int bit = (1 << i) & *data;
if (bit) bit = 1;
cout << bit;
}
cout << endl;
}
int main()
{
float f = 7.0;
bitPrint(f);
return 0;
}
This program prints 00000000000000000000011100000010
Since the sizeof(short) == 2 on your platform you get the first 2 bytes which are both zeros
Note that since size of types and possibly float implementation (not sure about this) are implementation defined different output can be seen on different platforms.
Well, let's see. First you write a float into the memory. It occupies 4 bytes, and it's value is 7. A float in the memory looks something like "sign bit -> exponent bits -> mantissa bits". I'm not sure how many bits are there for each part exactly, probably that depends on your platform.
Since the float's value is 7, it only occupies some of the least-significant bits on the right (I assume big-endian).
Your short pointer points to the beginning of the float, which means to the most significant bit. Since the value is greater than 0, the sign bit is zero. Since the float value is far on the right, we can say that those two most significant bytes are filled with zeros.
Now, provided that a size of short is 2, which means we will only take two bytes out of float's 4 bytes, we get our 0.
I believe though, that this result is rather UB and can differ on different platforms, compilers, etc.
Accessing data through a pointer to a different type than it was stored as gives (except in a few special cases) undefined behavour.
Firstly it's platform dependent how the data it stored so different systems may well give different values, and secondly the compiler might well generate code that doesn't even see the value you'd expect as it's allowed to do anything it likes when you do this (It's undefined behavour due to the strict aliases rules).
Having said that there are probably reasons why the number you are seeing is valid, but you can't rely on it unless you specifically know your platform will do what you expect, it's not guarenteed by the standard.
He's "pretty" sure it's not zero, he says that explicitly.
However, given that the representation of a short can be big-endian or little-endian, I wouldn't be so certain. In any case, this is a throwaway line at the end of a fifty-minute lecture so we can forgive him a little. It may be he came back in the next lecture with a clarification.
You would need to examine the underlying bits at (at least) a byte-by-byte level to understand what's going on.
define a float variable a, convert a to float & and int &, what does this mean? After the converting , a is a reference of itself? And why the two result is different?
#include <iostream>
using namespace std;
int
main(void)
{
float a = 1.0;
cout << (float &)a <<endl;
cout << (int &)a << endl;
return 0;
}
thinkpad ~ # ./a.out
1
1065353216
cout << (float &)a <<endl;
cout << (int &)a << endl;
The first one treats the bits in a like it's a float. The second one treats the bits in a like it's an int. The bits for float 1.0 just happen to be the bits for integer 1065353216.
It's basically the equivalent of:
float a = 1.0;
int* b = (int*) &a;
cout << a << endl;
cout << *b << endl;
(int &) a casts a to a reference to an integer. In other words, an integer reference to a. (Which, as I said, treats the contents of a as an integer.)
Edit: I'm looking around now to see if this is valid. I suspect that it's not. It's depends on the type being less than or equal to the actual size.
It means undefined behavior:-).
Seriously, it is a form of type punning. a is a float, but a is also a block of memory (typically four bytes) with bits in it. (float&)a means to treat that block of memory as if it were a float (in other words, what it actually is); (int&)a means to treat it as an int. Formally, accessing an object (such as a) through an lvalue expression with a type other than the actual type of the object is undefined behavior, unless the type is a character type. Practically, if the two types have the same size, I would expect the results to be a reinterpretation of the bit pattern.
In the case of a float, the bit pattern contains bits for the sign, an exponent and a mantissa. Typically, the exponent will use some excess-n notation, and only 0.0 will have 0 as an exponent. (Some representations, including the one used on PCs, will not store the high order bit of the mantissa, since in a normalized form in base 2, it must always be 1. In such cases, the stored mantissa for 1.0 will have all bits 0.) Also typically (and I don't know of any exceptions here), the exponent will be stored in the high order bits. The result is when you "type pun" a floating point value to a an integer of the same size, the value will be fairly large, regardless of the floating point value.
The values are different because interpreting a float as an int & (reference to int) throws the doors wide open. a is not an int, so pretty much anything could actually happen when you do that. As it happens, looking at that float like it's an int gives you 1065353216, but depending on the underlying machine architecture it could be 42 or an elephant in a pink tutu or even crash.
Note that this is not the same as casting to an int, which understands how to convert from float to int. Casting to int & just looks at bits in memory without understanding what the original meaning is.