C结构填充问题
C structure padding problems
struct something {
uint32_t a;
uint8_t b;
uint16_t c;
uint32_t x;
uint16_t y;
uint8_t z;
};
uint8_t *data = malloc(14);
struct something *s = (struct something *)data;
s->a = 1;
s->b = 2;
s->c = 3;
s->x = 4;
s->y = 5;
s->z = 6;
在 C 中执行此操作是否总是安全的,或者结构填充可能会导致问题?
编辑1(说清楚):是否保证data[0]..data[3]==1,data[4]==2,data [5]..data[6]==3, data[7]..data[10]==4, data[11]..data[12]==5 and data[13]==6?
编辑 2: 编辑 1 的小错误
这是不安全操作。编译器将以实现定义的方式添加填充。
一般来说,给定大小的成员将在该大小的倍数的偏移量上对齐。
鉴于完成填充的典型方式,此 struct
的大小很可能是 16 个字节。物理布局很可能(但不一定)如下所示:
struct something {
uint32_t a; // offset 0
uint8_t b; // offset 4
// 1 byte padding
uint16_t c; // offset 6
uint32_t x; // offset 8
uint16_t y; // offset 12
uint8_t z; // offset 14
// 1 byte padding
};
不要使用幻数。相反,使用 sizeof
运算符。
struct something *s = malloc(sizeof(struct something));
编辑:
如果您想增加 struct
以特定方式布局的可能性,请参阅此 guide to structure packing。如果您遵循此处的做法,很有可能(但不是 100%)您的 struct
将按照您期望的方式在内存中布局。
对于 gcc,您可以在 struct
上使用 __attribute__((packed))
从 struct
中删除填充。然而,这样做可能会导致性能下降或导致页面错误。 -Wpadded
和 -Wpacked
选项还可以告诉您有关填充的更多信息。
硬编码 14 非常顽皮。
为什么不使用 sizeof(struct something)
呢?这是一个 compile-time 可计算常量表达式,因此没有运行时开销。
您的预感是正确的:编译器保留在结构元素之间以及最终元素末尾插入填充的权利。 (注意,第一个元素的地址必须与 struct
的地址相同。)
struct something {
uint32_t a;
uint8_t b;
uint16_t c;
uint32_t x;
uint16_t y;
uint8_t z;
};
uint8_t *data = malloc(14);
struct something *s = (struct something *)data;
s->a = 1;
s->b = 2;
s->c = 3;
s->x = 4;
s->y = 5;
s->z = 6;
在 C 中执行此操作是否总是安全的,或者结构填充可能会导致问题?
编辑1(说清楚):是否保证data[0]..data[3]==1,data[4]==2,data [5]..data[6]==3, data[7]..data[10]==4, data[11]..data[12]==5 and data[13]==6?
编辑 2: 编辑 1 的小错误
这是不安全操作。编译器将以实现定义的方式添加填充。
一般来说,给定大小的成员将在该大小的倍数的偏移量上对齐。
鉴于完成填充的典型方式,此 struct
的大小很可能是 16 个字节。物理布局很可能(但不一定)如下所示:
struct something {
uint32_t a; // offset 0
uint8_t b; // offset 4
// 1 byte padding
uint16_t c; // offset 6
uint32_t x; // offset 8
uint16_t y; // offset 12
uint8_t z; // offset 14
// 1 byte padding
};
不要使用幻数。相反,使用 sizeof
运算符。
struct something *s = malloc(sizeof(struct something));
编辑:
如果您想增加 struct
以特定方式布局的可能性,请参阅此 guide to structure packing。如果您遵循此处的做法,很有可能(但不是 100%)您的 struct
将按照您期望的方式在内存中布局。
对于 gcc,您可以在 struct
上使用 __attribute__((packed))
从 struct
中删除填充。然而,这样做可能会导致性能下降或导致页面错误。 -Wpadded
和 -Wpacked
选项还可以告诉您有关填充的更多信息。
硬编码 14 非常顽皮。
为什么不使用 sizeof(struct something)
呢?这是一个 compile-time 可计算常量表达式,因此没有运行时开销。
您的预感是正确的:编译器保留在结构元素之间以及最终元素末尾插入填充的权利。 (注意,第一个元素的地址必须与 struct
的地址相同。)