内存对齐和位域

位域:这是结构的一种变形,允许对字中的位进行访问。

当我们定义一个结构体时,会分配多少字节呢?

以下列代码为例:

#include<iostream>
using namespace std;
int main()
{
	struct A {
		int a;
		int b;
		int c;
	};
	struct B {
		double d;
		int a;
		int b;
		int c;
	};
	struct C {
		char a;
		int b;
		int c;
		char d;
	};
	struct D {
		char a;
		int b;
		char d;
		B c;
	};
	cout << sizeof(A) << endl;
	cout << sizeof(B) << endl;
	cout << sizeof(C) << endl;
	cout << sizeof(D) << endl;
    return 0;
}

输出结果:

12

24

16

40

按常理来说,int分配4个字节.char分配1个字节,double分配8个字节,可为什么运行结果和我们想的不一样呢?

由此来说一下内存对齐的规定:

1.数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员自身大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。

编译器在给结构体开辟空间时,首先找到结构体中最宽的基本数据类型,然后寻找内存地址能被该基本数据类型所整除的位置,作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐数


2.结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)

为结构体的一个成员开辟空间之前,编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍,若是,则存放本成员,反之,则在本成员和上一个成员之间填充一定的字节,以达到整数倍的要求,也就是将预开辟空间的首地址后移几个字节。


3.结构体成员相对首地址偏移量必须是成员大小的整数倍,也就是内存对齐。


4.结构体总大小必须是对齐模数的整数倍,举个例子,你最后加出来的值为30,但是你得对齐模数是8,这时候你就要补充两个字节,让结构体大小为32.
5.结构体的对齐模数其实还是自定义的,具体格式为
#pragma back(需要的对其模数) 

以下为常见的对齐模数:


所以这就可以解释我们的4个结构体

struct A:       

最大对齐模数:4                                                                                                    

              

struct B:

最大对齐模数:8


补4:结构体总大小必须是对齐模数的整数倍

struct:C

最大对齐模数:4


第一次补3:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。

第二次补3:结构体总大小必须是对齐模数的整数倍

struct C:

最大对齐模数:8


位域(一个字节有八位):

有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

其形式为:struct 位域结构名 
{ 位域列表 };
其中位域列表的形式为: 类型说明符 位域名:位域长度

例如:

struct A

{

int a:8;

int b:4;

};

位域的要求:

1.一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。

struct A
{
char a : 4;

char b : 5;/*从下一单元开始存放*/
char c : 2;
};
cout << sizeof(A);
结果为2

2.由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。

3.位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。

struct B
{
char a : 1;
char : 2;/*该2位不能使用*/
char b : 3;
char c : 3;
};
结果为2

4.如果位域字段之间穿插着非位域字段,则不进行压缩;
struct k
{
int a : 2;
double b;
char c : 6;
};
cout << sizeof(k) << endl;
结果为24

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值