【问题标题】:As a programmer, what do I need to worry about when moving to 64-bit windows?作为一名程序员,在迁移到 64 位 Windows 时我需要担心什么?
【发布时间】:2010-10-07 08:31:57
【问题描述】:

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

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

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

编辑:这是nice list 的 64 位移植错误。

【问题讨论】:

  • 哪种语言?这有很大的不同:)
  • 我有很多 Win32 代码,用几种语言编写:C、C++ 和 VB6。我也有 C# 中的 .NET 代码——我不确定这是否会有同样的问题。
  • 了解为什么从 32 位到 64 位会出现问题。

标签: windows 32bit-64bit


【解决方案1】:

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

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

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

这什么时候重要?

  • 如果您现有的 32 位 EXE 是使用 /LARGEADDRESSAWARE MSVC 链接器选项构建的(或者通过其他方式在其 PE 标头中设置了 IMAGE_FILE_LARGE_ADDRESS_AWARE 标志,例如 editbin.exe),那么它们会得到在 64 位 Windows 中完整的 4 GB 虚拟地址空间,您必须使用 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 位移植问题.
  • 是的,documentation 表示不应使用/Wp64 进行编译,而应使用面向 64 位平台的编译器,但仅此一项不会在编译时捕获指针截断/扩展问题。使用面向 64 位的编译器为 64 位构建启用 /Wp64 编译器选项将在编译时捕获许多指针截断/扩展问题,这将节省您的时间运行。
  • 不幸的是,对于 MSVC 2008,这也会为每个翻译单元生成一个“命令行警告”,指出不推荐使用 /Wp64 选项。我可以看到为什么该选项在 32 位构建中被弃用(它是一个邪恶的 hack,需要注释您的许多 typedef),但不幸的是,它也被 64 位构建弃用(它实际上很有用)。

【讨论】:

  • 我同意强制分配高于 4 GB 线是非常重要的,但是如果您执行很多操作,使用 MEM_TOP_DOWN 会使分配变得非常缓慢。另一种强制分配具有“高”地址的方法是保留所有“低”地址。这是我使用过的一种技术:stackoverflow.com/a/29220631/1339280
【解决方案2】:
【解决方案3】:

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

顺便说一句,hanselman blogged 最近关于这个话题。

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

      【解决方案5】:

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

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

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

      【讨论】:

      • 正如其他人所指出的,假设某个整数大小会中断,还有很多事情可以做。我不认为直接说只要你不做任何设备驱动程序开发就可以了。
      • 我还没有看到 32 位应用程序在 64 位窗口上中断 - 只要它不是设备驱动程序。它们根本无法在 64 位 Windows 上运行。
      • 将一个指向 int 的指针用于许多项目和可以说是错误的样本,这是 32->64 位问题的常见来源。我还没有看到 OP 要求的语言结构的任何其他合法用法值得一提。
      • 虽然我同意重新检查所有硬编码路径的必要性 - 无论如何,在正确编写的 Windows 应用程序中不应该有任何(到系统目录)。有 API 函数可以获取正确的值,在非英语或非标准操作系统安装中,其他任何东西都可能并且将会失败。
      • +1 提到第三方库,这本身就是一个大问题,找到所有第三方依赖项的 64 位版本。
      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

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

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

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

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

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

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

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

        【讨论】:

        • 嗯,你应该使用en.wikipedia.org/wiki/Stdint.h 之类的东西来实际指定你想要的位。
        • 在Win64中int不是还是32位吗?
        • int 在 Win64 中仍然是 32 位 - 我猜不是那么明显 :)
        • @Calyth:关于使用标准类型的适当标头的评论大加 1。
        • 64 位通常意味着指针是 64 位的,并且必须有某种 64 位整数类型。有时 int 和 long 将是 32 位,而 long long 将是 64。这取决于实现。假设数据类型的大小通常很危险。
        【解决方案8】:

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

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

        【讨论】:

          猜你喜欢
          • 2011-07-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-11
          • 2010-09-30
          • 1970-01-01
          • 2011-02-13
          • 1970-01-01
          相关资源
          最近更新 更多