如何在 MSVC C++中迁移 x64 的 x86 代码

How to migrate x86 code for x64 in MSVC C++

本文关键字:x64 x86 代码 迁移 MSVC C++      更新时间:2023-10-16

我有一个针对x86的旧库。我需要迁移它才能使用 x64。但是存在一些指针地址问题。当我编译 x64 时,我丢失了指针地址。例如:

int main()
{
struct MY_STRUCT *p;
p = (struct MY_STRUCT *)malloc(sizeof(struct MY_STRUCT )); 
int hnd = (int)p;  //at this point, it tries to assign 64 bit address to a 32 bit variable. So half of the address is gone.
int ret;
ret=someFunct(hnd);
}
int someFunct(int Handle)
{
struct MY_STRUCT *p;
p = (struct MY_STRUCT *)(Handle); //at this point, p pointer takes an address value like 0x0000000012345678. And this causes access violation exception as expected.
return 0;
}

在 GCC 中,我记得可以使用编译器选项将 int 变量大小更改为 8bytes(64 位(。在 MSVC 中,我可以这样做吗?我可以将所有保存地址的变量更改为 64 位变量,但这是一个很大的库,因此需要对其进行深入测试以确保它与 x86 构建一样正常工作。任何建议将不胜感激。

在 GCC 中,我记得可以使用编译器选项将 int 变量大小更改为 8bytes(64 位(。

如果可以,最好不要这样做,其他代码/库可能不会预料到它。对于标头尤其如此,您不应该强制库的使用者依赖编译器标志。

我可以将所有保存地址的变量更改为 64 位变量,但这是一个很大的库,因此需要对其进行深入测试以确保它与 x86 构建一样正常工作。

如果写错了,这是您只需要处理的事情。还有很多其他陷阱,许多意外的内存覆盖和截断可能会被忽视,直到不幸的一天。

C 和 C++ 具有 typedef,这对于控制平台特定方面以及明确意图很有用(例如,我知道对uintptr_t的期望,我甚至不希望long long成为指针(。

确保你打开了所有的警告,我发现检查Windows/MSVC和Linux/GCC可以帮助发现一些事情,因为警告略有不同。例如:

int y = (int)ptr;

警告 C4311:"类型转换":指针从"int *"截断为"int">

首先,永远不要将指针转换为任何 int 类型,intlongunsigned等等。在你必须这样做的地方,有uintptr_tintptr_t它们将具有正确的大小,其他库/API 在使用 API 时可能有自己的类型可以使用(例如LONG_PTR在 Windows 中(,这应该可以帮助您支持他们正确执行的所有平台。

此外,由于没有什么是完美的,您使用的其他库和 API 可能需要完全不同的函数,例如,无论您使用任何 typedefs,Windows APISetWindowLong都无法处理 64 位上的指针大小值,但Microsoft添加了一个可以容纳指针的SetWindowLongPtr函数。

SetWindowLong(window, GWL_USERDATA, (LONG)ptr); // Not going to work on 64bit
SetWindowLong(window, GWL_USERDATA, (uintptr_t)ptr); // Still not going to work
SetWindowLongPtr(window, GWL_USERDATA, (LONG_PTR)ptr); // works on 32bit and 64bit

这取决于您的需求,这里有两个可能的选项:

  • 如果您需要对地址执行按位操作:使用uintptr_t而不是int,这将使您的代码可以通过不同的平台移植。
  • 如果您不需要对地址执行按位运算:void*而不是int就可以了。

我假设这段代码是 C(你不应该在 C++ 中以这种方式处理多态性和内存分配(。

相关文章: