使用指针缩小C ++中的类型转换

时间:2011-05-14 11:14:02

标签: c++ pointers type-conversion

我在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允许这么大的值?

3 个答案:

答案 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允许这么大的值?

intlong int通常具有相同的可能值范围。

答案 2 :(得分:1)

TheInt2 = *pTheLong2;

这会调用未定义的行为,因为C ++标准会保证哪个内存位置pTheLong2指向,因为它初始化为:

long int * pTheLong2 = &TheLong + 0x4;

&TheLong是变量TheLong的内存位置,pTheLong2被初始化为一个内存位置,该位置不是程序的一部分因此是非法的,或者它指向一个内存在程序本身内的位置,虽然你不知道究竟在哪里,C ++标准都没有给出任何指向它的保证。

因此,取消引用此类指针会调用未定义的行为。