确定C / C ++结构中元素对齐的算法

时间:2009-08-14 23:56:38

标签: c++ algorithm alignment

好的,请允许我重新提出这个问题,因为没有任何答案得到我真正感兴趣的内容(如果像这样的问题的全面编辑是假的话,请道歉。)

几点:

  • 这是使用与我正在测试的编译器不同的编译器进行离线分析,因此SIZEOF()或类似内容对我正在做的事情不起作用。
  • 我知道它是实现定义的,但我碰巧知道我感兴趣的实现,如下所示。

让我们创建一个名为pack的函数,它将一个称为alignment的整数和一个称为元素的整数元组作为输入。它输出另一个整数,称为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;
}

我想我想问的是“这个函数的反函数是什么?”,但是我不确定反演是否是正确的术语 - 我不记得曾经处理过具有多个输入的函数的反演,所以我可以使用一个不适用的术语。

存在我想要的东西(有点像);这里我提供了一个我们称之为determine_align的函数的伪代码。但是,这个函数有点天真,因为它只是用不同的输入一遍又一遍地调用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;
}

所以问题是,是否有更好的Determ_align实现?

谢谢,

7 个答案:

答案 0 :(得分:7)

C / C ++中结构成员的对齐完全是实现定义的。那里有一些保证,但我不明白他们会如何帮助你。

因此,没有通用的方法可以做你想要的。在特定实现的上下文中,您应该参考该实现的文档(如果已涵盖)。

答案 1 :(得分:5)

当选择如何将成员打包到struct实现时,不必遵循您在算法中描述的那种方案,尽管它是常见的方案。 (即,对齐的最小尺寸类型和优选的机器对准尺寸。)

您不必比较struct的总体大小来确定已应用于各个struct成员的填充。标准宏offsetof将给出从任何单个结构成员的struct开始的字节偏移量。

答案 2 :(得分: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)也有效。给定这两个函数/宏,您可以找出有关内存中结构布局的所有信息。

答案 3 :(得分:2)

老实说,我不确定你要做什么,而且我可能完全误解了你在寻找什么,但如果你想简单地确定一个结构的对齐要求是什么,下面的宏可能会有所帮助:

#define ALIGNMENT_OF( t ) offsetof( struct { char x; t test; }, test )

要确定foo结构的对齐方式,您可以执行以下操作:

ALIGNMENT_OF( foo);

如果这不是您最终要做的事情,那么宏可能有助于您提出的任何算法。

答案 4 :(得分:0)

您需要根据下一个字段的对齐方式填充,然后根据您在结构中看到的最大对齐方式填充最后一个元素。请注意,字段的实际对齐方式是其自然对齐的最小值以及该结构的包装。即,如果你有一个4字节的结构,一个double将与4个字节对齐,即使它的自然对齐是8。

您可以使用total_size+= total_size % min(packing, element.size);更快地完成内部循环如果packingelement.size是2的幂,您可以进一步优化它。

答案 5 :(得分:0)

如果问题只是您想要保证特定的对齐,那很容易。对于特定的对齐= 2 ^ n:

void* p = malloc( sizeof( _foo ) + alignment -1 );
p = (void*) ( ( (char*)(p) + alignment - 1 ) & ~alignment );

我忽略了保存到malloc返回的原始p。如果你打算释放这个内存,你需要将指针保存在某处。

答案 6 :(得分:0)

我不确定你想要在这里实现什么。正如Pavel Minaev所述,对齐由编译器处理,编译器又由平台的应用程序二进制接口约束,以便数据可由不同编译器编译的代码访问。以下文章讨论了需要实现调用约定的编译器上下文中的问题:

Christian Lindig和Norman Ramsey。 堆栈帧的声明组合。在Evelyn Duesterwald,编辑,Proc。第14届国际编译器构建会议,Springer,LNCS 2985,2004。