gcc结构中的内存对齐

我将应用程序移植到C中的ARM平台,该应用程序也在x86处理器上运行,并且必须向后兼容。

我现在有一些变量对齐的问题。 我已经阅读了__attribute__((aligned(4),packed))的gcc手册__attribute__((aligned(4),packed))我解释了所说的内容,因为struct的开头与4字节边界对齐,并且由于packed语句,内部保持不变。

最初我有这个,但偶尔它与4字节边界不对齐。

 typedef struct { unsigned int code; unsigned int length; unsigned int seq; unsigned int request; unsigned char nonce[16]; unsigned short crc; } __attribute__((packed)) CHALLENGE; 

所以我把它改成了这个。

 typedef struct { unsigned int code; unsigned int length; unsigned int seq; unsigned int request; unsigned char nonce[16]; unsigned short crc; } __attribute__((aligned(4),packed)) CHALLENGE; 

我之前说过的理解似乎是不正确的,因为结构现在都与4字节边界对齐,并且内部数据现在与4字节边界对齐,但由于字节顺序,结构的大小增加了大小从42到44个字节。 这个大小是至关重要的,因为我们有其他依赖于结构为42字节的应用程序。

有些人可以向我描述如何执行我需要的操作。 任何帮助深表感谢。

如果你依赖sizeof(yourstruct)是42字节,那么你将被一个不可移植的假设所sizeof(yourstruct) 。 你还没有说出这是为了什么,但结构内容的字节序似乎也很重要,所以你也可能与x86不匹配。

在这种情况下,我认为应对的唯一可靠方法是在重要的部分使用unsigned char[42] 。 首先编写一个精确的规范,准确说明这个42字节块中的哪些字段,以及哪个字节序,然后使用该定义编写一些代码,以便在它和可以与之交互的结构之间进行转换。 代码可能是一次性序列化代码(也称为编组),或者是一堆getter和setter。

这是为什么读取整个结构而不是成员失败的一个原因,应该避免。

在这种情况下,打包加上4对齐意味着将有两个字节的填充。 发生这种情况是因为大小必须兼容才能将类型存储在一个数组中,所有项仍然对齐为4。

我想你有类似的东西:

 read(fd, &obj, sizeof obj) 

因为您不想读取属于不同数据的那2个填充字节,所以必须明确指定大小:

 read(fd, &obj, 42) 

您可以保持可维护性:

 typedef struct { //... enum { read_size = 42 }; } __attribute__((aligned(4),packed)) CHALLENGE; // ... read(fd, &obj, obj.read_size) 

或者,如果您不能在C中使用C ++的某些function:

 typedef struct { //... } __attribute__((aligned(4),packed)) CHALLENGE; enum { CHALLENGE_read_size = 42 }; // ... read(fd, &obj, CHALLENGE_read_size) 

在下一次重构时,我强烈建议您逐个阅读每个成员,这可以很容易地封装在一个函数中。

你的真正目标是什么?

如果要以特定格式处理文件或线路上的数据,您应该做的是编写一些编组/序列化例程,这些例程在编译器结构之间移动数据,表示您希望如何处理数据内部的数据。程序和一个char数组,用于处理数据在有线/文件上的显示方式。

然后,所有需要仔细处理并且可能具有特定于平台的代码的是编组例程。 而且你可以编写一些讨厌的unit testing,以确保编组数据能够正确地进出结构,无论你可能需要移植到今天和未来的平台。

我猜想问题是42不能被4整除,所以如果你把这些结构中的几个连接起来就会失去对齐(例如为其中几个结构分配内存,用sizeof确定大小)。 大小为44会根据您的要求强制对齐这些情况。 但是,如果每个结构成员的内部偏移量保持不变,则可以将44字节结构视为42字节(只要您注意在正确的边界处对齐任何后续数据)。

尝试的一个技巧可能是将这两个结构放在一个联合类型中,并且只在每个这样的联合中使用42字节版本。

我一直在从Linux,Windows,Mac,C,Swift,Assembly等来回移动结构。

问题不在于它无法完成,问题在于你不能懒惰并且必须了解你的工具。

我不明白为什么你不能使用:

 typedef struct { unsigned int code; unsigned int length; unsigned int seq; unsigned int request; unsigned char nonce[16]; unsigned short crc; } __attribute__((packed)) CHALLENGE; 

如果你了解两者的情况,那么处于“伤害世界”的可能性是零。

最后,我不能为生活弄清楚你是如何获得42或44. Int是4个我们的8个字节(取决于编译器)。 这使得数字在16 + 16 + 2 = 34或32 + 16 + 2 = 50 – 假设它是真正的包装。

正如我所说,了解您的工具是您问题的一部分。

当我使用linux时,我发现通过echo 3 > /proc/cpu/alignment它会向我发出警告,并修复对齐问题。 这是一个解决方法,但它非常有助于找到结构未对齐的位置。