0

好的,请允许我重新提出这个问题,因为没有一个答案是我真正感兴趣的(如果对这样的问题进行全面编辑是虚假的,我们深表歉意)。

几点:

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

让我们创建一个名为 pack 的函数,它将一个整数(称为对齐)和一个整数元组(称为元素)作为输入。它输出另一个整数,称为大小。

该功能的工作原理如下:

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;
}

所以问题是,确定对齐有更好的实现吗?

谢谢,

4

7 回答 7

7

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

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

于 2009-08-15T00:03:55.493 回答
5

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

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

于 2009-08-15T00:24:21.227 回答
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) 也有效。给定这两个函数/宏,您可以弄清楚您需要了解的有关内存中结构布局的所有信息。

于 2009-08-15T00:01:22.097 回答
2

老实说,我不确定您要做什么,而且我可能完全误解了您要查找的内容,但是如果您想简单地确定结构的对齐要求是什么,则以下宏可能会有所帮助:

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

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

ALIGNMENT_OF( foo);

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

于 2009-08-15T02:18:04.380 回答
0

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

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

于 2009-08-15T00:02:54.043 回答
0

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

克里斯蒂安·林迪格和诺曼·拉姆齐。堆栈帧的声明性组合。在 Evelyn Duesterwald,编辑,Proc。第 14 届编译器构造国际会议,Springer,LNCS 2985,2004。

于 2012-12-27T17:26:41.650 回答
0

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

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

我忽略了保存到从 malloc 返回的原始 p 中。如果您打算释放此内存,则需要将该指针保存在某处。

于 2009-08-15T01:54:16.297 回答