C/C++:内存对齐(struct/union/field)

C/C++:内存对齐(struct/union/field)

原因

​ 字节对齐主要是为了提高内存的访问效率

  • 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

  • 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

对齐原则

  • 首个成员在与结构体变量偏移量为0的地址处

  • 各成员变量在存放的时候根据在结构中出现的顺序依次申请空间

  • 变量对齐数 = Min(编译器默认对齐数,该成员大小)

  • 各成员变量对齐到自身对齐数的整数倍(嵌套结构体对齐到自身最大对齐数整数倍

  • 结构体总大小为所有最大对齐数(包含嵌套结构体的成员对齐数)的整数倍
    在这里插入图片描述

示例

1.不同顺序排列

​ S1大小:12字节(1+3 +4 + 1+3);

​ S2大小:8字节(1+1+2 + 4);

​ 粗体为对齐填充字节。

struct S1
{
    char c1;
    int i;
    char c2;
};
struct S2
{
 	char c2;
    char c1;
    int i;
};

2.包含数组

​ student大小:24(10+2+4+1+3+4)

​ char name[10] 的本质是 10 个 char 变量,所以就把它当成 10 个 char 变量看就行了;

​ 粗体为对齐填充字节。

struct student
{
	char name[10];
	int age;
	char sex;
	float score;
};

3.结构体嵌套

​ student大小:32(4+13+7+8)

​ st1大小:48(4+4+32+1+7

struct student
{
	int num;
	char name[13];
	double gender;
};
struct st1
{
	int age;
	struct student s1;
	char sex;
};

4.联合体嵌套

联合体对齐方式要适合其中所有的成员(整个大小为最大对齐数的整数倍)

​ MyUnion大小:16(13+3

​ st1大小:32(4+4+16+1+7),union1应按成员最大字节对齐数(8)对齐,整个结构体为double倍数

union MyUnion
{
	int num;
	char name[13];
	double gender;
};
struct st1
{
	int age;
	union MyUnion union1;
	char sex;
};

pragma指令

  • 使用伪指令#pragma pack (n),C编译器将按照**min(n, sizeof(a))**个字节对齐(a为某类型变量,n= 1,2,4,8,16)。
  • 使用伪指令#pragma pack (),取消自定义字节对齐方式。

示例

1.S1大小:6(1+1+4)

​ S2大小:10(1+1+6+2),嵌套时按照min(2,sizeof(a))对齐

#pragma pack(2)
struct S1 {
	char a;
	long b;
};

struct S2 {
	char c;
	struct S1 d;
	char e;
};
#pragma pack()

2.S1大小:8(1+3+4)

​ S2大小:16(1+3+8+1+3),嵌套时按照min(8,sizeof(a))对齐

#pragma pack(8)
struct S1 {
	char a;
	long b;
};

struct S2 {
	char c;
	struct S1 d;
	char e;
};
#pragma pack()

位域

位域的声明和结构是类似的,有两个不同:

  • 位域的成员必须是 int、unsigned int、signed int、char等整形家族

  • 位域的成员名后边有一个冒号和一个数字

  • 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的

  • 一个位域必须存储在同一个字节中,不能跨两个字节

示例

​ 连续相同类型可使用位域来节省空间(S1)

​ 连续不同类型需按照对齐规则分配空间(S2)

​ 含位域的结构体嵌套对齐规则与普通嵌套相同(S3)

struct S1 {
	int i:8;
	int b:4;
	char a:3;
	double c;
};//16字节

struct S2 {
	int i:8;
	char a:3;
	int b : 4;
	double c;
};//24字节

struct S3 {
	char c;
	struct S2 d;
	char e;
};// 40字节

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中,结构体和类都是由多个成员变量组成的。为了在内存中高效地存储这些成员变量,编译器会对结构体和类进行内存字节对齐。 内存字节对齐是指将结构体或类中的成员变量按照一定的规则排列,使得每个成员变量的内存地址都是其长度的整数倍。这样一来,访问这些成员变量时就可以减少内存访问次数,提高访问效率。 内存字节对齐的规则如下: 1. 结构体或类的起始地址必须是其最宽基本类型成员的整数倍。 2. 结构体或类的每个成员变量相对于起始地址的偏移量必须是其类型大小的整数倍。 3. 结构体或类的总大小必须是其最宽基本类型成员大小的整数倍。 例如,一个结构体中有两个成员变量,一个是int类型,一个是char类型。如果按照默认的字节对齐规则排列,结构体的内存布局如下: ``` struct MyStruct { int a; char b; }; // 内存布局 // +---+---+ // | a | b | // +---+---+ ``` 这里,int类型占用4个字节,char类型占用1个字节。因此,编译器会按照4字节对齐方式排列结构体。由于int类型是最宽的基本类型,所以结构体的起始地址必须是4的倍数,而char类型则放在了4字节边界上。 需要注意的是,内存字节对齐规则可能会因为编译器的不同而产生变化。有些编译器允许开发者通过预处理指令来指定结构体的对齐方式,例如: ``` struct MyStruct { int a; char b; } __attribute__((aligned(8)))); ``` 这里,`__attribute__((aligned(8)))`表示MyStruct结构体需要以8字节对齐方式排列。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值