【发布时间】:2013-08-16 03:27:15
【问题描述】:
免责声明:这个问题是关于一个一般概念。我已经“简化”了这个问题,以便我可以在这里清楚地问它——无需提供它实际应用的整个上下文。我已经可以预见到诸如“你为什么要那样做?”之类的一堆 cmets。但是,如果这个问题可以从表面上看,我将不胜感激!
假设您想在运行时从一些预定义的结构中动态合成 C 中的一些数据结构。
我知道如何提出这个问题的最佳方法是通过代码示例。
在下文中,我们定义了两个结构:Foo 和 Bar。我还定义了一个结构FooBar 来说明编译时生成的复合类型和运行时生成的“动态合成”类型之间的至少一个区别。
#include <stdlib.h>
#include <stdio.h>
typedef struct Foo {
char junk1;
char junk2;
} Foo;
typedef struct Bar {
int junk3;
int junk4;
} Bar;
typedef struct FooBar {
Foo foo;
Bar bar;
} FooBar;
int main()
{
printf("Sizes: %li, %li, %li\n", sizeof(Foo), sizeof(Bar), sizeof(FooBar));
// Prints: Sizes: 2, 8, 12
// Because Foo is aligned on 1-byte boundaries and has total size of 2 bytes.
// Bar is aligned on 4-byte boundaries and has total size of 8 bytes.
// But FooBar is aligned on 4-byte boundaries due to the ints in Foo. Therefore,
// the compiler added 2-bytes of padding after the foo member.
// The following "works", but only allocates 10 bytes, and
// "Bar" members are now "misaligned":
void * syntheticFooBar = malloc(sizeof(Foo) + sizeof(Bar));
((Foo*)syntheticFooBar)->junk1 = 1;
((Foo*)syntheticFooBar)->junk2 = 2;
((Bar*)(syntheticFooBar + sizeof(Foo)))->junk3 = 3;
((Bar*)(syntheticFooBar + sizeof(Foo)))->junk4 = 4;
free(syntheticFooBar);
return 0;
}
所以我的问题是:
1.) 缺乏正确的数据对齐会对性能造成多大的影响?考虑到访问合成结构的“成员”所涉及的开销,数据对齐是否是一个重要的影响因素?
2.) 考虑到运行时综合的限制,有没有更好的方法来做到这一点?
【问题讨论】:
-
您始终可以为要执行此操作的结构关联类型标记并将它们相互嵌入。假设 foo 扩展了 bar,那么 struct foo 中就会有一个 struct bar。使用 containerof 宏可以得到这些扩展。
-
您是否要避免添加填充?
-
@VaughnCato - 不,我并不是要避免添加填充 - 如果有办法以某种方式即时计算和添加填充(如果这很重要,性能方面),我很乐意这样做。
-
您必须确保每个成员都有正确的对齐方式。在您的示例中,您会看到
Bar具有 4 字节对齐(例如),因此您将在合成结构中的Foo和Bar之间添加两个额外字节。 -
这完全取决于处理器。 x86 可能没问题(虽然我不记得
double是否是这样,这往往是最受限制的类型),但如果对齐不正确,肯定会有处理器出现内存总线故障.主要事实是这段代码在 C 标准下具有未指定的行为。您永远无法确定将来的某些系统更改不会导致您的代码核心转储。我会尽快摆脱这个想法。
标签: c struct memory-alignment