我有一个C#背景。我非常喜欢像C这样的低级语言。
在C#中,struct
的内存由编译器默认布局。编译器可以隐式地重新排序数据字段或填充字段之间的附加位。因此,我必须指定一些特殊属性来覆盖此行为以进行精确布局。
AFAIK,C默认情况下不会重新排序或对齐struct
的内存布局。但是,我听说有一个很难找到的例外。
C的内存布局行为是什么?什么应该重新排序/对齐而不是?
答案 0 :(得分:101)
它是特定于实现的,但实际上规则(在没有#pragma pack
之类的情况下)是:
sizeof(T)
字节对齐。所以,给定以下结构:
struct ST
{
char ch1;
short s;
char ch2;
long long ll;
int i;
};
ch1
位于偏移0 s
偏移2 ch2
位于偏移4处,紧接在s ll
偏移8 i
位于偏移16处,就在ll 所以sizeof(ST)
是24。
通过重新排列成员可以减少到16个字节以避免填充:
struct ST
{
long long ll; // @ 0
int i; // @ 8
short s; // @ 12
char ch1; // @ 14
char ch2; // @ 15
} ST;
答案 1 :(得分:99)
在C中,允许编译器为每种基本类型指定一些对齐。通常,对齐是类型的大小。但它完全是针对具体实施的。
引入了填充字节,因此每个对象都正确对齐。不允许重新排序。
可能每个远程现代编译器都实现#pragma pack
,它允许控制填充并将其留给程序员以符合ABI。 (但这绝对是非标准的。)
来自C99§6.7.2.1:
12 a的每个非位字段成员 结构或联合对象是对齐的 以实现定义的方式 适合其类型。
13 结构对象,非位域 成员和单位 位字段驻留具有地址 增加他们的顺序 宣布。指向结构的指针 对象,适当转换,指向 其初始成员(或如果该成员 是一个位域,然后到单位 它居住的地方),反之亦然。 一个内部可能有未命名的填充 结构对象,但不是它的 开始。
答案 2 :(得分:9)
您可以先阅读data structure alignment wikipedia article,以便更好地了解数据对齐。
数据对齐意味着将数据放入存储器偏移量等于字大小的某个倍数,这会因CPU处理内存的方式而提高系统性能。为了对齐数据,可能需要在最后一个数据结构的末尾和下一个数据结构的开头之间插入一些无意义的字节,即数据结构填充。
来自GCC文档的6.54.8 Structure-Packing Pragmas:
与Microsoft兼容 Windows编译器,GCC支持一套 #pragma指令改变了 最大对齐成员 结构(零宽度除外) 比特场,工会和班级 随后定义。 n值 以下总是要求小 两个权力并指定新的 以字节为单位的对齐。
pragma pack(n)只是设置新的路线。
pragma pack()将对齐设置为
中的对齐方式 编译开始时的效果(见 也是命令行选项 -fpack-struct [=]参见Code Gen Options)。pragma pack(push [,n])按下
上的当前对齐设置 内部堆栈然后可选 设置新的路线。- 醇>
pragma pack(pop)将对齐设置恢复为
中保存的设置 内部堆栈的顶部(和 删除该堆栈条目)。注意enter code here
#pragma pack([n])不会影响此内部堆栈;因此它是 可能有#pragma pack(推) 接着是多个#pragma pack(n) 实例并由单个最终确定 #pragma pack(pop)。某些目标,例如i386和powerpc, 支持ms_struct #pragma 根据文件列出一个结构 __attribute __((ms_struct))。
pragma ms_struct on打开声明的结构的布局。
pragma ms_struct off关闭声明的结构的布局。
- 醇>
pragma ms_struct reset返回默认布局。