Eon*_*nil 76 c struct memory-layout
我有一个C#背景.我非常喜欢像C这样的低级语言.
在C#中,struct默认情况下由编译器布局内存.编译器可以隐式地重新排序数据字段或填充字段之间的附加位.因此,我必须指定一些特殊属性来覆盖此行为以获得精确布局.
AFAIK,C struct默认情况下不重新排序或对齐a的内存布局.但是,我听说有一个很难找到的例外.
什么是C的内存布局行为?什么应该重新订购/对齐而不是?
dan*_*n04 105
它是特定于实现的,但在实践中规则(在没有#pragma pack或类似的情况下)是:
sizeof(T)字节.所以,给定以下结构:
struct ST
{
char ch1;
short s;
char ch2;
long long ll;
int i;
};
Run Code Online (Sandbox Code Playgroud)
ch1 在偏移0处s 在抵消2ch2 在s之后立即偏移4ll 在抵消8i 在ll之后,在偏移16处那sizeof(ST)是24.
通过重新排列成员可以将其减少到16个字节以避免填充:
struct ST
{
long long ll; // @ 0
int i; // @ 8
short s; // @ 12
char ch1; // @ 14
char ch2; // @ 15
} ST;
Run Code Online (Sandbox Code Playgroud)
Pot*_*ter 102
在C中,允许编译器为每种基本类型指定一些对齐.通常,对齐是类型的大小.但它完全是针对具体实施的.
引入填充字节,以便每个对象都正确对齐.不允许重新排序.
可能每个远程现代编译器都实现#pragma pack了允许控制填充并将其留给程序员以符合ABI.(但它严格来说是非标准的.)
从C99§6.7.2.1:
12结构或联合对象的每个非位字段成员都以适合其类型的实现定义方式对齐.
13在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址.指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然.结构对象中可能存在未命名的填充,但不是在其开头.
jsc*_*ier 10
您可以从阅读数据结构对齐维基百科文章开始,以更好地理解数据对齐.
来自维基百科的文章:
数据对齐意味着将数据放入存储器偏移量等于字大小的某个倍数,这会因CPU处理内存的方式而提高系统性能.为了对齐数据,可能需要在最后一个数据结构的末尾和下一个数据结构的开始之间插入一些无意义的字节,即数据结构填充.
为了与Microsoft Windows编译器兼容,GCC支持一组#pragma指令,这些指令可以更改随后定义的结构(除了零宽度位域),联合和类的成员的最大对齐.下面的n值始终需要是2的小幂,并以字节为单位指定新的对齐方式.
pragma pack(n)只是设置新的对齐方式.
pragma pack()将对齐设置为其中的对齐方式
编译开始时的效果(另请参阅命令行选项-fpack-struct [=]请参阅代码选项选项).pragma pack(push [,n])按下当前对齐设置
内部堆栈然后可选地设置新的对齐.pragma pack(pop)将对齐设置恢复为保存的对齐设置
内部堆栈的顶部(并删除该堆栈条目).请注意,#pragma pack(n)#pragma pack([n])不会影响此内部堆栈; 因此可以使用#pragma pack(push),然后是多个#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返回默认布局.