使用版本相关数据文件的软件与 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
并且它们的字节顺序可能需要转换。)
在最简单的情况下,当程序独立于任何外部数据库时,可以编写以下形式的内容:
#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
并且它们的字节顺序可能需要转换。)