3

我意识到通常 C 和 C++ 标准为编译器编写者提供了很大的自由度。但特别是它保证像 C 结构成员这样的 POD 类型必须按照它们在结构定义中列出的顺序排列在内存中,并且大多数编译器都提供了扩展,让您可以修复成员的对齐方式。因此,如果您有一个定义结构的标头并手动指定其成员的对齐方式,然后使用标头使用不同的编译器编译两个应用程序,那么一个应用程序是否应该能够将结构的实例写入共享内存而另一个应用程序能够正确读取它吗?

我假设包含的类型的大小在同一架构上的两个编译器中是一致的(它必须已经是同一个平台,因为我们正在谈论共享内存)。我意识到这对于某些类型并不总是正确的(例如 GCC 和 MSVC 64 位中的 long 与 long long),但现在有 uint16_t、uint32_t 等类型,并且 float 和 double 由 IEEE 标准指定。

4

5 回答 5

3

只要您可以保证完全相同的内存布局,包括偏移量,并且数据类型在两个编译器之间具有相同的大小,那么可以。因为此时结构在数据访问方面是相同的。

于 2010-01-20T16:39:32.517 回答
2

是的,当然。我已经做过很多次了。无论是编译并链接混合代码,还是在机器之间传输结构格式的数据,问题和解决方案都是相同的。

在过去糟糕的日子里,这种情况经常发生在集成 MS C 和几乎任何其他东西时:Borland Turbo C、DEC VAX C、Greenhills C。

简单的部分是让各种数据类型的字节数一致。例如short,一侧的 32 位编译器与另一端int的 16 位编译器相同。由于声明结构的通用源代码通常是一件好事,因此一些中肯的声明很有帮助:

typedef  signed long     s32;
typedef  signed short    s16;
typedef  signed char     s8;
typedef  unsigned long   u32;
typedef  unsigned short  u16;
typedef  unsigned char   u8;
...

Microsoft C 是最烦人的。它的默认值是将成员填充为 16 位对齐,并且可能更多地使用 64 位代码。x86 上的其他编译器不填充成员。

struct {
    int   count;
    char  type;
    char  code;
    char  data [100];
} variable;

似乎 的偏移量code应该是 之后的下一个字节type,但可能在其间插入了一个填充字节。修复通常是

#ifdef _MSC_VER    // if it's any Microsoft compiler
 #pragma pack(1)   // byte align structure members--that is, no padding
#endif

还有一个编译器命令行选项可以执行相同的操作。

于 2010-01-20T17:54:36.710 回答
0

请参阅您的编译器手册。

大多数编译器都提供扩展,让您修复成员的对齐方式

您是否将自己限制在那些编译器和相互兼容的#pragma align风格上?如果是这样,安全性由它们的规范决定。

出于可移植性的考虑,您最好放弃#pragma align并依赖您的 ABI,这可能会为您平台的所有编译器的合规性提供“合理的”标准。

由于 C 和 C++ 标准允许任何确定性结构布局方法,它们本质上是不相关的。

于 2010-04-15T00:05:29.920 回答
0

确实有可能,您只需要确保所涉及的所有编译器都从相同的代码生成相同的数据结构。测试这一点的一种方法是编写一个示例程序,该程序创建一个结构并将其写入二进制文件。在十六进制编辑器中打开生成的文件并验证它们是否相同。或者,您可以将结构转换为数组uint8_t并将各个字节转储到屏幕上。

确保数据大小相同的一种方法是使用int16_t(来自 stdint.h)之类的数据类型,而不是可能会在编译器之间改变大小的普通旧数据类型int(尽管这在同一平台上运行的两个编译器中很少见)。

这并不像听起来那么困难。有许多预编译的库可以与多个编译器一起使用。关键是构建一个测试程序,让您验证两个编译器是否平等地对待结构。

于 2010-01-20T17:40:36.170 回答
0

如果您需要编译器 1 编译的库 1 中的 struct 用于编译器 2 编译的库 2,那么除了数据类型大小之外,内存的布局方式也很重要。

于 2010-01-20T16:51:24.083 回答