对齐到8的原因是什么?

发布于 2024-12-11 16:04:15 字数 731 浏览 0 评论 0原文

  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呢?

  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;

The above is extracted from MySQL source,

why bother to align to 8?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

草莓酥 2024-12-18 16:04:15

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

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

It's an optimization to allow more efficient access to the structures in memory by the CPU.

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

风渺 2024-12-18 16:04:15

原因 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 的倍数,否则它会变慢4.

Reason 1: Address computations are faster and smaller.

On x86 as well as some other architectures, it is more efficient to access elements of an array if the element size is a "nice, round number". For the definition of "nice, round number", learn x86 assembly. But you can see the effects of accessing arrays with differently sized elements in assembly for the following code:

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

When N is 23 (size of the above structure without padding):

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

When N is 24 (size of the above structure with padding):

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

When N is 32 (size of the above structure with additional padding):

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

Notice how complicated the code is for accessing an element in an array with 23-byte elements.

Reason 2: For on-disk structures, it allows other elements in file to be accessed with aligned loads and stores.

It looks like the structure appears on disk. With padding, a 32-bit word can appear directly after the structure and be aligned. This makes it faster to access -- the compiler automatically does this for structures in memory, but you need to do it manually for structures on disk. Some architectures will even crash if you try to access unaligned data.

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

The above code will crash a SPARC if sizeof(header) is not a multiple of 4, and on x86 it will be slower unless sizeof(header) is not a multiple of 4.

┼── 2024-12-18 16:04:15

如果标头结构位于数组中,则数组的所有元素将以相同的方式对齐。不然的话,就不会是这样了。您可以查看下面的代码/输出来验证这一点。

如果 Dani 在他们的评论中是正确的,则该用户打算投射诸如 file_version 到一个uint32_t,那么这种对齐方式就非常重要了。

一些代码的

#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

If the header struct is in an array, all elements of the array will be aligned in the same manner. Otherwise, that would not be the case. You can take a look at the code / output below to verify that.

If Dani, in their comment, is correct that the users of this intend to cast things like file_version to a uint32_t, then this kind of alignment would be very important.

Some code

#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]));
}

The output

size padded:      24
size unpadded:    23
size padded[2]:   48
size unpadded[2]: 46
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文