在C中将32位应用程序转换为64位应用程序

我目前正致力于将32位应用程序转换为C语言中的64位应用程序。此应用程序目前正在开发x86架构(Windows,osx,Unix,Linux)。 因此,在开始编码之前,我想知道在转换应用程序时我需要考虑什么。

  1. 找出谁写了它。 他们是白痴吗? 他们是几年前的吗? 你能问他们问题吗? 他们熟悉多平台和系统的存在吗? 了解程序作者的思维方式将帮助您在遇到问题时理解问题。
  2. 启动并运行64位计算机/构建环境。
  3. 用int替换long。 要完全清楚LONGlong
  4. 替换(int)&x强制转换并使用uintptr_tintptr_t(unsigned int)&x键入
  5. 审计任何依赖于将结构转换为char*以使用它进行指针运算的东西。
  6. 如果您假设4 = sizeof(void*)表达式搜索\ <4 \>
  7. 耐心点。 当您发现问题时,请查看是否存在相同问题的其他地方,并将解决方案包装在宏中。
  8. 尽量不要使用#ifdef RUN64或类似的东西。 如果128位平台变得流行,你会后悔的。
  9. 根据某些集中式宏来封装所有更改,这些宏将隐藏程序中其他位置的可移植性差异。
  10. 使用覆盖测试仪来确保您已覆盖所有内容(如果适用)

EDIT根据评论的建议添加了uintptr_t注释。

尚未提到的一个潜在问题是,如果您的应用程序从磁盘读取或写入二进制数据(例如,使用fread读取结构数组),您将不得不非常仔细地检查并且可能最终有两个读取器:一个用于传统文件和一个64位文件。 或者,如果您小心使用头文件中的uint32_t等类型,则可以重新定义结构以进行逐位兼容。 无论如何, 二进制I / O是值得注意的事情。

这实际上取决于应用程序及其编码方式。 有些代码可以用64位编译器重新编译,它只会工作,但通常只有在代码设计时考虑了可移植性时才会发生这种情况。

如果代码有很多关于本机类型和指针大小的假设,如果它有很多位打包或使用字节指定的协议与外部进程对话但是使用一些关于本机类型大小的假设然后可能需要一些或大量的工作才能获得干净的编译。

几乎每个演员和编译器警告都是需要签出的红旗。 如果代码不是“警告干净”,那么这也表明可能需要做很多工作。

如果您为您的值使用了正确的类型 – 例如。 size_tptrdiff_tuintptr_tstdint.h中适当的固定大小的int类型 – 并且没有硬编码值大小,您的代码应该开箱即用。

切换到64位时遇到的主要问题是指针的大小不同(64位而不是32位)整数的大小和长度的大小也可能不同,具体取决于平台。

为什么这是个问题? 好吧,它不是,除非你的代码假设sizeof(int)== sizeof(void *)。 这可能导致令人讨厌的指针错误。

嗯,从根本上说,变化的数量相当小,但如果应用程序没有经过仔细编写,开始时可以稍微移植,那么它仍然是一项重大任务。

主要区别在于指针是64位宽, 大多数其他数据类型没有变化。 int仍然是32位,而long可能仍然是32位。 因此,如果你的代码在int和指针之间进行转换,那就会破坏。 类似地,依赖于成员的特定偏移量的任何结构或类似物可能会破坏,因为其他成员现在可能更大,因此更改偏移量。

当然,你的代码首先不应该依赖这些技巧,所以在一个理想的世界里,这根本不是问题,你可以简单地重新编译,一切都会起作用。 但你可能不是生活在一个理想的世界……;)

C中32位和64位编程的两个主要区别是sizeof(void *)和sizeof(long)。 您将面临的主要问题是大多数Unix系统使用I32LP64标准,该标准定义长达64位,Win64使用IL32LLP64标准,该标准定义了长达32位。 如果需要支持跨平台编译,则可能需要为32位和64位整数使用一组基于体系结构的typedef,以确保所有代码的行为一致。 作为C99标准的一部分,它作为stdint.h的一部分提供。 如果您不使用C99编译器,则可能需要滚动自己的等效编译器

如其他地方所述,转换的主要问题是假设sizeof(int)== sizeof(long)== sizeof(void *)的代码,支持已写入磁盘的数据的代码和跨平台IPC的代码。

有关此背后的历史的详细介绍,请查看ACM Queue中的这篇文章 。

已经有很多好的答案。

考虑使用Gimpel Lint 。 它可以准确地指出有问题的构造类型。 如果您的体验与我的一样,它也会向您显示与32/64位端口无关的系统中的大量错误。

所有关于开发人员的64位:

有关64位开发的文章

链接集合64位资源

工具Viva64