确定 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); 使您的内部循环更快,如果packingelement.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++ 结构中元素对齐的算法的主要内容,如果未能解决你的问题,请参考以下文章

结构对齐 C/C++

结构体内存对齐——

1分钟了解C语言正确使用字节对齐及#pragma pack的方法

C语言 | 结构体内存对齐

C/C++ struct/class/union内存对齐

转C/C++ struct/class/union内存对齐