结构体、位段、共用体

结构体内存对齐

为什么要有内存对齐?

第一点:平台原因
平台原因也是移植原因:不是所有的硬件平台都能访问 任意地址上的任意数据。某些硬件平台只能在某些特殊地址处取值。
第二点:性能原因
数据结构(尤其是栈)应该尽可能的在自然边界上对齐。原因是:为了访问未对齐的内存处理器需要做两次内存访问,对齐的内存只需要一次访问。
typedef struct S
{
	char ch;
	int i;
}S;

int main()
{
	S s;
	return 0;
}

假设在32位机器下操作,那么读写操作时可以访问32位即4个字节。

因此我们得出:

结构体的内存对齐是拿 空间时间的做法。

如何计算结构体大小

先介绍结构体对齐的规则:

  1. 第一个成员在与结构体变量偏移量为0的地址处。

  1. 其他成员变量要对齐到对齐数的整数倍地址处。

对齐数 = min(编译器默认的对齐数,结构体成员大小)

  1. 结构体总大小为最大对齐数的整数倍。

  1. 对于嵌套结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍,结构体的整体大小就是所有最大对齐数(包括嵌套结构体的对齐数)的整数倍。

vs下的默认对齐数是8
Linux下没有默认对齐数。自身的大小就是默认对齐数

上代码:

struct A
{
	char a;
	int b;
	char c;
};

int main()
{
	printf("%d\n", sizeof(struct A));
	return 0;
}

交换两个成员变量:

struct A
{
	char a;
	char c;
	int b;
};

int main()
{
	printf("%d\n",sizeof(struct A));
	return 0;
}

嵌套的结构体

struct A
{
	char a;
	char c;
	int b;
};
struct B
{
	char ch;
	struct A a;
	int c;
};

int main()
{
	printf("%d\n",sizeof(struct B));
	return 0;
}

修改默认对齐数

当对齐方式不合适的时候,可以修改对齐方式

#pragma pack(4)  //设置默认对齐数为4
struct A
{
	char a;
	char c;
	int b;
};
#pragma pack()  //取消设置的对齐数,还原为默认 

位段

什么是位段:

位段的声明和结构是类似的,有两个不同:
1、位段的成员必须是int ,unsigned int,char 或 signed int.
2、位段的成员后边有一个冒号和一个数字。
struct S
{
	int a : 3; //a占3个bit位
	int b : 5; //b占5个bit位
};

int main()
{
	printf("%d\n", sizeof(struct S));
	return 0;
}

这是因为一个int 类型是4个字节,而a只占3个bit位,还剩29个bit位,b又占了5个bit位,还剩下24个bit位。所以4个字节就足够了。


来看下边代码:

struct C
{
	char a : 3;
	char b : 6;
	char c : 2;
	char d : 4;
};

int main()
{
	struct C c = { 0 };
	c.a = 10;
	c.b = 12;
	c.c = 4;
	c.d = 7;
	return 0;
}
位段是无可移植性的。
c标准也没规定位段的成员在内存是从左往右还是从右往左分配的。但是从上例子可以看出在vs编译器下是从右往左分配的。
反正就是:少用位段!!! 😒 除了适合位段的特定场景!!

总结:

与结构相比,位段节省了空间。但是有跨平台的问题存在。

联合体(共用体)

union关键字

联合体的特点:

联合的成员是共用同一块内存空间的,联合体的大小 至少是最大成员的大小。当最大成员大小不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍。
  • 可以使用位段判断当前机器的大小端存储

int check_sys()
{
	union Un
	{
		char ch;
		int i;
	}u;
	u.i = 1;
	return u.ch;
}

int main()
{
	int ret = check_sys();
	if (1 == ret)
	{
		printf("小端存储\n");
	}
	else
	{
		printf("大端存储\n");
	}
	return 0;
}

OK!!! 💪

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值