32

我最近的大部分编程都是在使用 C/C++/C#/VB6 的 32 位 Windows 上进行的。最近,我的客户询问我的代码是否可以在 64 位 Windows 上运行。

我想知道我可能使用的哪些遗留功能会在 64 位 Windows 上中断?我需要考虑和担心哪些现实问题?

显然,我将在 64 位操作系统上测试我的代码,但我想知道要查找哪些常见问题。我更关心现有的二进制文件,但我愿意就重新编译时(在可能的情况下)时要担心的问题发表评论。

编辑:这是一个很好的 64 位移植错误列表。

4

8 回答 8

22

就我而言,将 C/C++ 代码移植到 64 位 Windows 的最重要的事情是在启用分配(注册表值)的情况下测试您的应用程序,MEM_TOP_DOWNAllocationPreference4-Gigabyte Tuning中所述:

要强制分配在较低地址之前从较高地址分配以进行测试,请MEM_TOP_DOWN在调用时指定VirtualAlloc或将以下注册表值设置为 0x100000:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\AllocationPreference

这什么时候有关系?

  • /LARGEADDRESSAWARE如果您有使用MSVC 链接器选项构建的现有 32 位 EXE (或IMAGE_FILE_LARGE_ADDRESS_AWARE通过其他方式在其 PE 标头中设置标志,例如editbin.exe),那么它们将获得完整的 4 GB 64 位虚拟地址空间Windows,您必须使用AllocationPreference注册表值集对其进行测试。
  • 如果您有现有的 32 位 DLL 可能由大地址感知 EXE 加载,则必须使用AllocationPreference注册表值集对其进行测试。
  • 如果将 C/C++ 代码重新编译为 64 位 EXE 或 DLL,则必须使用AllocationPreference注册表值集对其进行测试。

如果您的 C/C++ 应用程序属于这三个类别之一并且您不使用MEM_TOP_DOWN分配进行测试,则测试不太可能在您的代码中捕获任何指针截断/签名错误。

第二个最重要的事情是,如果您使用 MSVC 并且正在为 64 位重新编译 C/C++ 代码,则为您的64 位构建使用/Wp64编译器选项

  • 这将导致编译器对截断指针或将较小的整数类型扩展为指针的类型转换发出警告(即使reinterpret_cast使用 C 样式转换),以及其他一些 64 位移植问题。
  • 是的,文档说与其一起/Wp64编译,不如使用针对 64 位平台的编译器,但仅此一项就不会在编译时捕获指针截断/扩展问题。使用面向 64 位的编译器/Wp64为 64 位构建启用编译器选项将在编译时捕获许多指针截断/扩展问题,从长远来看,这将节省您的时间。
  • 不幸的是,对于 MSVC 2008,这也会为每个翻译单元生成一个“命令行警告”,说明该/Wp64选项已被弃用。我可以看到为什么该选项在 32 位构建中被弃用(它是一个邪恶的 hack,需要注释您的许多 typedef),但不幸的是,它也被 64 位构建弃用(它实际上很有用)。
于 2009-02-13T07:50:59.400 回答
4

如果您拥有 100% 的“类型安全托管代码”,则迁移 .NET 代码可能会更容易。直接复制到64位平台,在64位CLR下运行成功即可。检查此MSDN 链接,了解将 32 位托管代码迁移到 64 位。

顺便说一句,hanselman最近在博客上讨论了这个话题。

于 2009-02-13T01:14:11.927 回答
2

如果您谈论的是 32 位程序,那么您几乎无需担心,因为 Windows 64 将在仿真下将它们作为 32 位运行。未来 Windows 版本(例如 Windows 7)的任何问题都可能是不兼容问题,而不是 64 位操作系统的问题。

但是,如果您的托管代码是为“任何 CPU”目标平台编译的,并且您调用非托管代码(例如 PInvoke),或者依赖于其他程序集,那么需要注意一些事项。Scott Hanselman 关于 x86/x64 CLR 的帖子涵盖了这一点,并且很好地解释了 Win32/64 上的 CLR。

在开发 64 位本机程序时,64 位 Windows 编程指南是一个很好的指南。它主要归结为指针和数据类型的大小:)

于 2009-02-13T01:16:44.370 回答
2

32 位程序可以在 64 位窗口上正常运行。当然,只要您不进行任何设备驱动程序类型的开发。

如果您第一次将软件编译为 64 位软件,则需要注意以下事项:

  • 指针是 64 位宽,而 int 是 32 位。不要将指针存储在整数中,您的代码会中断。
  • 64 位进程需要 64 位 DLL。如果您依赖第三方 DLL,请确保它们也以 64 位提供。如果您需要在 32 位进程和 64 位进程之间进行通信,您将需要 Windows 上许多不同的 IPC 方式中的一些。直接调用函数是没有问题的。
  • 64 位 Windows 上的系统目录与 32 位 Windows 上的不同。如果您有一些硬编码路径,您可能需要再次检查它们。
于 2009-02-13T01:52:28.747 回答
1

如果您出于任何原因进行 DLL 注入,您将遇到麻烦。

于 2009-02-14T18:16:41.290 回答
0

从 C/C++ 的角度来看......

一件显而易见的事情是 int 的大小将变为 8 个字节而不是 4 个字节。如果您的任何代码依赖于它,您可能会得到意想不到的结果。结构和变量对齐可能会发生变化。您可以使用#pragma pack 克服它,但我对对齐和打包不是很流利。

如果您使用其中包含整数的任何联合,则行为可能会改变。

如果您使用任何位域结构,基于整数的额外 32 位可能会导致混淆。符号位不会是您认为的位置。

如果您编写任何十六进制常量并期望符号变为负数,您可能会遇到问题。示例 0x8000000 是作为日志的负数,或 32 位整数。0x80000000 作为 64 位平台上的整数是一个正数。要直接设置符号位,您必须使用 0x80000000 00000000 (嵌入空间仅供阅读)

我也希望 size__t 能够适当增长。如果您基于 MAX_INT 进行任何分配,它们会更大。

为了避免这些类型的大小异常,我通常坚持使用 long 而不是 int。

于 2009-02-13T01:24:04.680 回答
0

32 位仿真真的是防弹的吗?我已经看到注册表的布局略有不同。我只是想知道哪些典型的事情不起作用......

此外,C:\windows\SYSTEM32 目录只能包含 64 位 DLL。如果你有一个 32 位的 DLL,你需要把它放在 C:\windows\syswow64\

于 2009-02-13T06:10:26.520 回答