使用版本相关数据文件的软件与 32 位系统兼容的最佳实践?

Best practice for compatibility with 32-bit systems for softwares using version dependent data files?

在最简单的情况下,当程序独立于任何外部数据库时,可以编写以下形式的内容:

#include <stdint.h>
#if UINTPTR_MAX == 0xffffffff
/* 32-bit */
typedef some_type_for_32_bit_version Type;

#elif UINTPTR_MAX == 0xffffffffffffffff
/* 64-bit */
typedef some_type_for_64_bit_version Type;
#endif

并继续使用所需的类型。

现在假设程序在开头读取了一些 meta/data 文件,一些位表示文件是为 32 位还是 64 位构建的(为 32 位构建的文件应该在 64 位上工作同样,为 64 位构建的文件应该只能在 64 位上工作)。对于这两种情况,该程序的操作可能几乎相同,但存在细微差别,例如一些变量对于 32 位是 uint32_t,对于 64 位是 uint64_t。

一个糟糕的解决方案是从读取该位开始,拥有该变量的不同版本和任何使用它的 struct/union/function,并且有大量不必要的 if 语句。

我想有一些加载程序读取该字节,写入另一个文件中的某些 #define,运行 是一个编译器,最后 运行 是生成的程序 - 但是似乎太讨厌了,我对每次 运行.

都要忍受编译时间的想法并不感到兴奋

有什么通用的设计吗?特定于 c 的东西? c++?

您需要做两件事:

  • 您只想编写一个可用于两种配置的解析器,具体取决于文件中的标志。在这里有用的概念是模板。

    在 C++ 中,您可以使用模板使一个函数或 class 适用于多种类型。在 C 中没有真正好的机制,因此保持动态部分尽可能小以避免代码重复更为重要。模板的一个简单模拟是将所有代码定义为宏,并将类型作为参数,并为两种类型实例化两次。

  • 在运行时动态选择变体。在这里可以使更复杂的设置更易于管理的一个概念是动态调度。在那里您将创建一个通用接口并根据类型实例化 32 位或 64 位变体。

    在 C++ 中,这将是一个带有虚方法的接口 class。在 C 中,这可以很容易地复制为包含函数指针的结构。

我假设在这种情况下,对于程序的 32 位和 64 位版本,将这些值存储在本机指针大小的整数中就足够了,但是如果它们需要保留其原始文件大小,则需要更多代码程序需要是动态的。

根据您的描述,我建议您使用如下简单的方法:

// When reading the file:
bool flagIs64bit = readThatFlag();
if (currentArchIs32bit() && flagIs64bit) {
  return NotSupported;
}

// At the core of the parser:
uintptr_t readType(void *p) {
  if (flagIs64bit) {
    return (uintptr_t)*(uint64_t*)p;
  } else {
    return (uintptr_t)*(uint32_t*)p;
  }
}

(对设计的评论:二进制文件通常应该独立于它们所使用的体系结构。这样它们就可以与尽可能多的系统兼容。这意味着应该只使用明确的宽度类型(u)intNN_t 并且它们的字节顺序可能需要转换。)