Narrowing type conversion in C++ using pointers
I have been having some problems with downward type conversion in C++ using pointers, and before I came up with the idea of doing it this way Google basically told me this is impossible and it wasn't covered in any books I learned C++ from. I figured this would work...
long int TheLong=723330;
int TheInt1=0;
int TheInt2=0;开发者_运维技巧
long int * pTheLong1 = &TheLong;
long int * pTheLong2 = &TheLong + 0x4;
TheInt1 = *pTheLong1;
TheInt2 = *pTheLong2;
cout << "The double is " << TheLong << " which is "
<< TheInt1 << " * " << TheInt2 << "\n";
The increment on line five might not be correct but the output has me worried that my C compiler I am using gcc 3.4.2 is automatically turning TheInt1 into a long int or something. The output looks like this...
The double is 723330 which is 723330 * 4067360
The output from TheInt1 is impossibly high, and the output from TheInt2 is absent.
I have three questions...
Am I even on the right track?
What is the proper increment for line five?
Why the hell is TheInt1/TheInt2 allowing such a large value?
int
is probably 32 bit, which gives it a range of -2*10^9 to 2*10^9.
In the line long int * pTheLong2 = &TheLong + 0x4;
you are doing pointer arithmetic to a long int*
, which means the address will increase by the size of 0x4
long int
s. I guess you are assuming that long int
is twice the size of int
. This is absolutely not guaranteed, but probably true if you are compiling in 64 bit mode. So you want to add half the size of a long int
-- exactly the size of an int
under your assumption -- to your pointer. int * pTheLong2 = (int*)(&TheLong) + 1;
achieves this.
You are on the right track, but please keep in mind, as others have pointed out, that you are now exploring undefined behaviour. This means that portability is broken and optimization flags may very well change the behaviour.
By the way, a more correct thing to output (assuming that the machine is little-endian) would be:
cout << "The long is " << TheLong << " which is "
<< TheInt1 << " + " << TheInt2 << " * 2^32" << endl;
For completeness' sake, a well-defined conversion of a 32 bit integer to two 16 bit ones:
#include <cstdint>
#include <iostream>
int main() {
uint32_t fullInt = 723330;
uint16_t lowBits = (fullInt >> 0) & 0x0000FFFF;
uint16_t highBits = (fullInt >> 16) & 0x0000FFFF;
std::cout << fullInt << " = "
<< lowBits << " + " << highBits << " * 2^16"
<< std::endl;
return 0;
}
Output: 723330 = 2434 + 11 * 2^16
Am I even on the right track?
Probably not. You seem confused.
What is the proper increment for line five?
There are none. Pointer arithmetic is possible only inside arrays, you have no arrays here. So
long int * pTheLong2 = &TheLong + 0x4;
is undefined behavior and any value other than 0 (and possibly 1) by which you'd replace 0x4 would also be UB.
Why the hell is TheInt1/TheInt2 allowing such a large value?
int
and long int
often have the same range of possible values.
TheInt2 = *pTheLong2;
This invokes undefined behavior, because the C++ Standard does not give any guarantee as to which memory location pTheLong2
is pointing to, as it's initlialized as:
long int * pTheLong2 = &TheLong + 0x4;
&TheLong
is a memory location of the variable TheLong
and pTheLong2
is initialized to a memory location which is either not a part of the program hence illegal, or its pointing to a memory location within the program itself, though you don't know where exactly, neither the C++ Standard gives any guarantee where it's pointing to.
Hence, dereferencing such a pointer invokes undefined behavior.
精彩评论