匿名结构体与结构体自引用
匿名结构体
- 虽然第一个结构体与第二个结构体的成员变量相同,但是编译器会把上面的两个声明当成完全不同的两个类型。假如:pm=&s;是非法的。
结构体的自引用
- 结构体中不能包含一个类型为该结构本身的成员。如果需要使用结构体自引用时,必须包含结构本身的指针变量来当成员。
- 如果使用typedef对结构体进行类型重定义时,声明结构本身的指针变量来当成员时,需要加上struct。
结构体内存对齐
为什么要有内存对齐
- 首先我们要明白CPU不是我们想象中,想怎么样读取内存就可以怎么样读取内存的。
- 对于CPU来说,有可能一次读取2个字节,4个字节或8个字节,而且都是相当于0地址处来读取的。
- 举一个易懂的例子,假设一个double的数据从0地址开始存储,那么他的存储位置为0 1 2 3 4 5 6 7 。如果CPU一次读取4个字节,那么从0地址处开始依次读4个字节,只需读取两步就可以。如果double的数据从1地址开始存储,那么他的存储位置为1 2 3 4 5 6 7 8,则CPU需要先读取0 1 2 3,4 5 6 7,8 9 10 11。读取三步才能读取到这个double的数据。
- 如果采用内存对齐,这个double的数据只会从0,4,8,12……这样的位置开始存储。CPU可以从0,4,8,12……这样的位置直接开始读,因为CPU相当于0地址处一次读取4的字节刚好吻合。
- 所以结构体的内存对齐是拿空间来换取时间的做法。当然还有其他的原因,比如平台原因,性能原因。
内存对齐规则
- 不管怎么声明结构体,第一个成员在与结构体变量偏移量为0的地址处开始存放。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的偏移量处。
- 对齐数=编译器默认的一个对齐数与该成员空间大小的较小值。
- 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
最后,在设计结构体的时候,既要满足对齐,又要节省空间的方法是:让占用空间小的成员尽量集中在一起。
#pragma pack的使用与offsetof的模拟
1.
- #pragma pack(N)是用来修改编译器的默认对齐数。
- #pragma pack( )取消设置的默认对齐数,还原为默认。
2.
- offsetof是用来计算结构体中某变量相对于首地址的偏移量。
- offsetof不是函数,而是一个#define定义的宏。
- offsetof(结构体名字,结构体成员名)返回的类型是size_t。