文章目录
- 1 结构体内存对齐
- 2 位段式结构体
- 2.1 格式
- 2.2 成员类型
- 2.3 空间开辟
- 2.4 示例
- 2.4.1 示例1
- 2.4.2 示例2
1 结构体内存对齐
- 首成员对齐规则
- 结构体的第一个成员从偏移量为0的地址处开始存放,即与结构体的首地址对齐。
- 其他成员对齐规则
- 其他成员变量的存放地址必须对齐到其对齐数的整数倍;
- 对齐数的定义为:该成员变量自身大小与编译器默认对齐数的较小值:
- 在Visual Studio中,默认对齐数为8;
- 如果编译器没有默认对齐数,则成员变量的大小即为它的对齐数,如GCC。
- 结构体总大小
- 结构体的总大小必须是其所有成员中最大对齐数的整数倍。如果不足,编译器会在末尾填充字节以满足对齐要求。
- 嵌套结构体的对齐规则
- 如果结构体中嵌套了结构体,则嵌套的结构体需要对齐到其自身最大对齐数的整数倍处;
- 结构体总大小必须是其所有成员(含嵌套结构体成员)中最大对齐数的整数倍。
另外:
- 计算成员偏移量
- offsetof宏可以用来计算结构体成员相对于起始位置的偏移量。
- 修改默认对齐数
- #pragma pack(n)可以将默认对齐数设置为n;
- #pragma pack()可以取消默认对齐数设置,恢复到最初的默认值。
2 位段式结构体
2.1 格式
位段式结构体的定义与普通结构体类似,但在成员声明时需要指定所占的位数。格式如下:
struct 结构体名 {
类型 成员名 : 位数;
// 其他成员...
};
2.2 成员类型
位段的成员类型必须是整数类型,如下图所示:
分类 | 类型 | 说明 |
---|---|---|
基本型 | int | 有符号整型,通常是32位 |
基本型 | unsigned int | 无符号整型,通常是32位 |
基本型 | char | 有符号字符型,8位 |
基本型 | unsigned char | 无符号字符型,8位 |
基本型 | _Bool | 布尔型,C99引入,通常为1位 |
扩展型 | short | 有符号短整型,通常是16位 |
扩展型 | unsigned short | 无符号短整型,通常是16位 |
扩展型 | long | 有符号长整型,通常是32位或64位 |
扩展型 | unsigned long | 无符号长整型,通常是32位或64位 |
扩展型 | long long | 有符号长长整型,通常是64位 |
扩展型 | unsigned long long | 无符号长长整型,通常是64位 |
扩展型 | enum | 枚举类型,底层通常是int |
2.3 空间开辟
位段的空间开辟规则可以归纳为以下几点:
- 新空间的开辟要满足基本的结构体内存对齐规则(参考“1 结构体内存对齐”);
- 新空间的开辟要基于成员类型(如char类型1字节、short类型2字节、int类型4字节);
- 类型相同的位段可以共享空间,类型不同的位段不能共享空间;
- 如果当前开辟空间的剩余位数不足以容纳下一个位段,则重新开辟一个空间。
2.4 示例
2.4.1 示例1
类型相同的位段共享空间,示例代码如下所示:
typedef struct {
unsigned int a : 10; // 10位
unsigned int b : 8; // 8位
unsigned int c : 4; // 4位
} bitField1;
int main()
{
//
printf("Size of bitField1 : %zu bytes.\n", sizeof(bitField1));
//
return 0;
}
运行结果如下图所示:
代码及运行结果分析如下:
- 开辟4字节空间,成员a占10个比特位,还剩下22个比特位;
- 成员b和成员a类型相同,可与a共享已开辟的空间,占用剩余22个比特位中的8个比特位,还剩下14个比特位;
- 成员c和成员a、b类型相同,可与a、b共享已开辟的空间,占用剩余14个比特位中的4个比特位,还剩下10个比特位。
2.4.2 示例2
类型不同的位段共享空间,示例代码如下所示:
typedef struct {
unsigned int a : 20; // 20位,类型为 unsigned int
unsigned short b : 10; // 10位,类型为 unsigned short
} bitField2;
int main()
{
//
printf("Size of bitField2 : %zu bytes.\n", sizeof(bitField2));
//
return 0;
}
运行结果如下图所示:
代码及运行结果分析如下:
- 从偏移量0处开辟4字节空间,成员a占20个比特位,还剩下12个比特位;
- 注意:尽管当前已开辟的空间的剩余比特位(12个)足以容纳成员b(10个比特位),但是,因为成员b与成员a类型不同,不可共享已开辟的空间,需要重新开辟空间;从偏移量4处开辟2字节空间,成员b占10个比特位,还剩下6个比特位;
- 另外,结构体总大小必须是其所有成员中最大对齐数的整数倍。