编译器能否通过将它们放置在非对齐地址中来避免在结构中填充?

问题描述 投票:0回答:1

假设我们有结构

struct {
    char c;
    uint32_t i;
} my_struct_t;

根据我在网上看到的内容,编译器在字符与 uint32 之间填充 3 个字节以进行对齐。 理论上编译器可以不填充,但总是将结构放在内存地址 3mod(4) 中吗?

c struct memory-alignment
1个回答
3
投票

这不会工作,因为它不会与 C 的其他功能一起工作,特别是数组和动态内存分配。

假设

uint32_t
有四个字节的对齐要求,并且编译器在
struct { char c; uint32_t i; } my_struct_t;
中不使用填充,并且还要求它从 3 modulo 4 的地址开始。

考虑当程序员声明一个

my_struct_t
数组时会发生什么,如
my_struct_t x[5];
x[0]
起始于 3 模 4 的地址,长度为 5 个字节,因此
x[1]
起始于 3+5 = 8 模 4 的地址,这与 0 模 4 一致。然后成员
x[1].i
位于 1 模 4 的地址,因此它未对齐。

还要考虑当程序员为这样的结构动态分配内存时会发生什么,如

my_struct_t *p = malloc(sizeof *p);
malloc
例程仅被告知要分配多少字节。它不知道它们的用途。这在当前 C 实现中的工作方式是
malloc
总是返回与任何普通对象类型(C 2018 6.2.8 2 中列出的类型)对齐的内存。例如,如果
double
具有八个字节的对齐要求,并且它是任何普通对象类型中最严格的对齐要求,那么该 C 实现的
malloc
总是返回一个八字节的倍数的地址。由于这个地址是八字节的倍数,所以也是四字节的倍数和两字节的倍数和一字节的倍数,所以它适用于普通对象的任何对齐要求。 (一些
malloc
例程旨在返回更严格对齐的内存,原因超出了本答案的范围,例如当最严格的普通对象对齐要求仅为八个字节时,内存始终为 16 字节的倍数。)

您可以更改 C 语言以允许永远不能在数组中并且永远不能动态分配的类型,或者您可以引入新版本的

malloc
它被告知要提供什么对齐方式,但这些更改会使语言复杂化并没有被发现是有用的。

© www.soinside.com 2019 - 2024. All rights reserved.