与8对齐的原因是什么?

时间:2011-10-24 02:51:49

标签: c memory-alignment

  struct {              /* Fileheader */
    uchar file_version[4];
    uchar options[2];
    uchar header_length[2];
    uchar state_info_length[2];
    uchar base_info_length[2];
    uchar base_pos[2];
    uchar key_parts[2];         /* Key parts */
    uchar unique_key_parts[2];      /* Key parts + unique parts */
    uchar keys;             /* number of keys in file */
    uchar uniques;          /* number of UNIQUE definitions */
    uchar language;         /* Language for indexes */
    uchar max_block_size_index;     /* max keyblock size */
    uchar fulltext_keys;
    uchar not_used;                     /* To align to 8 */
  } header;

以上内容摘自MySQL源代码,

为什么还要与8对齐?

3 个答案:

答案 0 :(得分:6)

这是一种优化,可以让CPU更有效地访问内存中的结构。

http://en.wikipedia.org/wiki/Data_structure_alignment

答案 1 :(得分:3)

原因1:地址计算越来越快。

在x86以及其他一些体系结构中,如果元素大小是“漂亮的圆形数字”,则访问数组元素会更有效。对于“nice,round number”的定义,请学习x86程序集。但是您可以在以下代码中看到使用不同大小的元素访问数组的效果:

struct s { char c[N]; };
int func(struct s *p, int i) { return p[i].c[0]; }

当N为23时(没有填充的上述结构的大小):

leaq    (%rsi,%rsi,2), %rax
salq    $3, %rax
subq    %rsi, %rax
movsbl  (%rax,%rdi),%eax

当N为24(具有填充的上述结构的大小)时:

leaq    (%rsi,%rsi,2), %rax
movsbl  (%rdi,%rax,8),%eax

当N为32时(附加填充的上述结构的大小):

salq    $5, %rsi
movsbl  (%rsi,%rdi),%eax

请注意代码访问具有23个字节元素的数组中元素的复杂程度。

原因2:对于磁盘结构,它允许使用对齐的加载和存储来访问文件中的其他元素。

看起来结构出现在磁盘上。使用填充,32位字可以直接出现在结构之后并对齐。这使得访问速度更快 - 编译器自动为内存中的结构执行此操作,但您需要手动为磁盘上的结构执行此操作。如果您尝试访问未对齐的数据,某些体系结构甚至会崩溃。

unsigned char *data = ...;
header *h = (header *) data;
do_something_with(h);
uint32_t x = *(uint32_t *) (data + sizeof(header));

如果sizeof(header)不是4的倍数,则上述代码会使SPARC崩溃,而在x86上,除非sizeof(header)不是4的倍数,否则上述代码会慢一些。

答案 2 :(得分:1)

如果头结构在数组中,则数组的所有元素将以相同的方式对齐。否则,情况就不是这样了。您可以查看下面的代码/输出来验证。

如果Dani在他们的评论中是正确的,那么打算将file_version之类的内容转换为uint32_t,那么这种对齐非常重要。< / p>

一些代码

#include <stdio.h>

struct padded {
    unsigned char file_version[4];
    unsigned char options[2];
    unsigned char header_length[2];
    unsigned char state_info_length[2];
    unsigned char base_info_length[2];
    unsigned char base_pos[2];
    unsigned char key_parts[2];
    unsigned char unique_key_parts[2];
    unsigned char keys;
    unsigned char uniques;
    unsigned char language;
    unsigned char max_block_size_index;
    unsigned char fulltext_keys;
    unsigned char not_used;
};

struct unpadded {
    unsigned char file_version[4];
    unsigned char options[2];
    unsigned char header_length[2];
    unsigned char state_info_length[2];
    unsigned char base_info_length[2];
    unsigned char base_pos[2];
    unsigned char key_parts[2];
    unsigned char unique_key_parts[2];
    unsigned char keys;
    unsigned char uniques;
    unsigned char language;
    unsigned char max_block_size_index;
    unsigned char fulltext_keys;
};

int main() {
    printf("size padded:      %lu\n", sizeof(struct padded));
    printf("size unpadded:    %lu\n", sizeof(struct unpadded));

    printf("size padded[2]:   %lu\n", sizeof(struct padded[2]));
    printf("size unpadded[2]: %lu\n", sizeof(struct unpadded[2]));
}

输出

size padded:      24
size unpadded:    23
size padded[2]:   48
size unpadded[2]: 46