我在C ++中使用指针进行向下类型转换时遇到了一些问题,在我想出这样做之前,谷歌基本上告诉我这是不可能的,并且在我学过C ++的任何书中都没有涉及从。我认为这样可行......
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";
第五行的增量可能不正确但输出让我担心我使用gcc 3.4.2的C编译器会自动将TheInt1转换为long int或其他东西。输出看起来像这样......
双倍是723330,即723330 * 4067360
TheInt1的输出不可能高,并且没有TheInt2的输出。
我有三个问题......
我是否在正确的轨道上?
第五行的适当增量是什么?
为什么地狱是TheInt1 / TheInt2允许这么大的值?
答案 0 :(得分:5)
int
可能是32位,这使得它的范围为-2 * 10 ^ 9到2 * 10 ^ 9.
在行long int * pTheLong2 = &TheLong + 0x4;
中,您正在对long int*
进行指针算术运算,这意味着地址将增加0x4
long int
的大小。我猜你假设long int
的大小是int
的两倍。这绝对不能保证,但如果您在64位模式下进行编译,可能也是如此。因此,您希望将long int
的一半大小 - 正是您假设的int
的大小 - 加到指针上。 int * pTheLong2 = (int*)(&TheLong) + 1;
实现了这一点。
你走在正确的轨道上,但请记住,正如其他人所指出的那样,你现在正在探索未定义的行为。这意味着可移植性被破坏,优化标志可能会很好地改变行为。
顺便说一下,输出更正确的东西(假设机器是小端)将是:
cout << "The long is " << TheLong << " which is "
<< TheInt1 << " + " << TheInt2 << " * 2^32" << endl;
为了完整起见,将32位整数转换为两位16位整数:
#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;
}
输出:723330 = 2434 + 11 * 2^16
答案 1 :(得分:2)
我是否在正确的轨道上?
可能不是。你好像很困惑。
第五行的适当增量是什么?
没有。指针算法只能在数组内部进行,这里没有数组。所以
long int * pTheLong2 = &TheLong + 0x4;
是未定义的行为,除了0(可能是1)之外的任何替换0x4的值也将是UB。
为什么地狱是TheInt1 / TheInt2允许这么大的值?
int
和long int
通常具有相同的可能值范围。
答案 2 :(得分:1)
TheInt2 = *pTheLong2;
这会调用未定义的行为,因为C ++标准不会保证哪个内存位置pTheLong2
指向,因为它初始化为:
long int * pTheLong2 = &TheLong + 0x4;
&TheLong
是变量TheLong
的内存位置,pTheLong2
被初始化为一个内存位置,该位置不是程序的一部分因此是非法的,或者它指向一个内存在程序本身内的位置,虽然你不知道究竟在哪里,C ++标准都没有给出任何指向它的保证。
因此,取消引用此类指针会调用未定义的行为。