确定 C/C++ 结构中元素对齐的算法
Posted
技术标签:
【中文标题】确定 C/C++ 结构中元素对齐的算法【英文标题】:Algorithm for determining Alignment of elements in C/C++ structs 【发布时间】:2009-08-14 23:56:37 【问题描述】:好的,请允许我重新问这个问题,因为没有一个答案是我真正感兴趣的(如果像这样对问题进行全面编辑是虚假的,我们深表歉意)。
几点:
这是使用与我正在测试的编译器不同的编译器进行的离线分析,因此 SIZEOF() 或类似方法不适用于我正在做的事情。 我知道它是由实现定义的,但我碰巧知道我感兴趣的实现,如下所示。让我们创建一个名为 pack 的函数,它将一个整数作为输入,称为对齐,以及一个整数元组,称为元素。它输出另一个整数,称为 size。
函数的作用如下:
int pack (int alignment, int[] elements)
total_size = 0;
foreach( element in elements )
while( total_size % min(alignment, element) != 0 ) ++total_size;
total_size += element;
while( total_size % packing != 0 ) ++total_size;
return total_size;
我想我想问的是“这个函数的逆是什么?”,但我不确定逆是否是正确的术语——我不记得曾经处理过具有多个输入的函数的逆,所以我可能只是使用了一个不适用的术语。
存在我想要的东西(有点);在这里,我提供了一个我们将称为确定对齐的函数的伪代码。不过,这个函数有点幼稚,因为它只是用不同的输入一遍又一遍地调用 pack,直到它得到它期望的答案(或失败)。
int determine_align(int total_size, int[] elements)
for(packing = 1,2,4,...,64) // expected answers.
size_at_cur_packing = pack(packing, elements);
if(actual_size == size_at_cur_packing)
return packing;
return unknown;
所以问题是,确定对齐有没有更好的实现?
谢谢,
【问题讨论】:
【参考方案1】:C/C++ 中结构成员的对齐方式完全由实现定义。那里有一些保证,但我看不出它们会如何帮助你。
因此,没有通用的方法来做你想做的事。在特定实现的上下文中,您应该参考涵盖该实现的文档(如果已涵盖)。
【讨论】:
【参考方案2】:在选择如何将成员打包到struct
中时,实现不必遵循您在算法中描述的那种方案,尽管它是一种常见方案。 (即对齐的类型的最小尺寸和首选机器对齐尺寸。)
不过,您不必比较 struct
的整体大小来确定已应用于单个 struct
成员的填充。标准宏 offsetof
将给出从任何单个结构成员的 struct
开始的字节偏移量。
【讨论】:
【参考方案3】:我让编译器为我做对齐。
在 gcc 中,
typedef struct _foo
u8 v1 __attribute__((aligned(4)));
u16 v2 __attribute__((aligned(4)));
u32 v3 __attribute__((aligned(8)));
u8 v1 __attribute__((aligned(4)));
foo;
编辑:请注意 sizeof(foo) 将返回正确的值,包括任何填充。
Edit2:offsetof(foo, v2) 也可以。有了这两个函数/宏,您就可以弄清楚您需要了解的有关内存中结构布局的所有信息。
【讨论】:
【参考方案4】:老实说,我不确定您要做什么,而且我可能完全误解了您要查找的内容,但是如果您想简单地确定结构的对齐要求是什么,请使用以下宏可能会有所帮助:
#define ALIGNMENT_OF( t ) offsetof( struct char x; t test; , test )
要确定foo
结构的对齐方式,您可以这样做:
ALIGNMENT_OF( foo);
如果这不是您最终想要做的事情,那么宏可能有助于您提出的任何算法。
【讨论】:
【参考方案5】:您需要根据下一个字段的对齐方式填充,然后根据您在结构中看到的最大对齐方式填充最后一个元素。请注意,字段的实际对齐方式是其自然对齐方式和该结构的包装中的最小值。即,如果你有一个 4 字节的结构体,一个 double 将被对齐到 4 个字节,即使它的自然对齐是 8。
您可以使用total_size+= total_size % min(packing, element.size);
使您的内部循环更快,如果packing
和element.size
是2 的幂,您可以进一步优化它。
【讨论】:
【参考方案6】:如果问题只是您想保证特定的对齐方式,那很容易。对于特定的对齐方式=2^n:
void* p = malloc( sizeof( _foo ) + alignment -1 );
p = (void*) ( ( (char*)(p) + alignment - 1 ) & ~alignment );
我忽略了保存到从 malloc 返回的原始 p。如果您打算释放此内存,则需要将该指针保存在某处。
【讨论】:
是& ~(alignment - 1)
不是& ~alignment
【参考方案7】:
我不确定你想在这里实现什么。正如Pavel Minaev 所说,对齐由编译器处理,而编译器又受平台的应用程序二进制接口的约束,以获取可由不同编译器编译的代码访问的数据。以下论文讨论了需要实现调用约定的编译器上下文中的问题:
克里斯蒂安·林迪格和诺曼·拉姆齐。 堆栈帧的声明性组合。在 Evelyn Duesterwald,编辑,Proc。第 14 届编译器构造国际会议,Springer,LNCS 2985,2004。
【讨论】:
以上是关于确定 C/C++ 结构中元素对齐的算法的主要内容,如果未能解决你的问题,请参考以下文章