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

Narrowing type conversion in C++ using pointers

本文关键字:类型转换 C++ 缩小 指针      更新时间:2023-10-16

我在使用指针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 转换为长整型或其他东西。输出如下所示...

双倍是723330,

即723330*4067360

TheInt1 的输出高得不可思议,而 TheInt2 的输出不存在。

我有三个问题...

我甚至走在正确的轨道上吗?

第五行的正确增量是多少?

为什么 TheInt1/TheInt2 允许这么大的值?

int可能是 32 位,这给了它 -2*10^9 到 2*10^9 的范围。

long int * pTheLong2 = &TheLong + 0x4;行中,您正在对long int*进行指针算术,这意味着地址将增加 0x4 long int s 的大小。我猜你假设long intint大小的两倍.这绝对不能保证,但如果以 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

我甚至走在正确的轨道上吗?

应该不会。 你似乎很困惑。

第五行的正确增量是多少?

没有。 指针算术只能在数组内部使用,这里没有数组。 所以

long int * pTheLong2 = &TheLong + 0x4;

是未定义的行为,并且要替换0x4的 0(可能为 1)以外的任何值也将是 UB。

为什么 TheInt1/TheInt2 允许这么大的值?

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

TheInt2 = *pTheLong2;

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

long int * pTheLong2 = &TheLong + 0x4;

&TheLong是变量TheLong的内存位置,pTheLong2被初始化为内存位置,该内存位置要么不是程序的一部分,因此是非法的,要么指向程序本身内的内存位置,尽管您不知道确切的位置,C++标准都没有提供任何保证它指向的位置。

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