自定义类型(结构体对齐,位段,枚举,联合体的讲解)

大家都知道的是在c中不仅有其内置的类型,还有一些类型是我们可以自己定义的,比如结构体,枚举,联合体等。

1.结构体

声明结构体的关键字是struct,其语法注意事项比较简单,这里不再多说,想给大家说的是结构体中一个关键的知识点,那就是结构体对齐问题,结构体对齐到底有什么用呢?他的用处就是可以让我们很好的计算出结构体占用了多少空间。打个比方:

struct stu
{
	char name[10];
	char tele[12];
	int agr;
};
int main()
{
	struct stu a;
	printf("%d", sizeof(a));
	return 0;
}

这段代码中的结构体到底占用了多少字节呢?其实很多人的想法是,因为name,占用了10个字节,tele占用12,age占用4,所以总的大小是26,如果只是简单的相加的话,那就大错特错了,此时我们应该要注意他的对齐问题。那么,问题来了,什么是结构体对齐呢?下面就给大家说说:

解释一下第四点:在嵌套了结构体的情况下,这个嵌套的结构体应该放到自己成员的最大对齐数的整数倍处,而整体的大小就是最大对齐数的整数倍。

就以上面的代码为列:因为char name占用了10个字节,而char tele占用12个字节,因为他们的对齐数都是1,所以他们占用的空间是22个字节,也就是到了偏移地址为21的地方,因为int age占用4个字节,其对齐数是4,所以22不是他的整数倍处,所以此时就要浪费空间,到偏移处为24的地方来存放他,总的大小是28个字节,而这个结构体的最大对齐数是4,28是4的整数倍,所以此结构体的大小就是28个字节,我们来看看运行结果。

 

而他在内存中的存放是这样的,

 

这个就是他的存放原理,如果概念大家理解不了,就看看这个图,会更加好理解一些。下面来个结构体嵌套的列子:

struct stu
{
	char name[10];
	char tele[12];
	int agr;
};
struct s
{
	double b;
	struct stu a;
	int i;
};
int main()
{
	struct s m;
	printf("%d", sizeof(m));
	return 0;
}

代码如上:他的大小是多少呢?首先因为第一个成员是double b所以它占用了偏移量0-7的内存,接下来就是嵌套的结构体了,嵌套的结构体中,成员的最大对齐数是4,所以8是他的整数倍,所以它占用了8-35的内存空间,最后一个是int i的,对齐数4,而36是他的整数倍,所以他占用的就是36-39的内存空间,而这个结构体的最大对齐数是8,所以总的40是他的整数倍,所以这个结构体的大小就是40,打印结果:

这个图我就不画了,和上面的原理相同。以上就是结构体对齐的原理和列子了

2.位段

什么位段呢?他又有什么用呢?其实位段指得就是结构体中以位以单位来指定其成员所占内存的长度,其成员成为位段或位域。而他其实可以是节省内存的,他的表示方如下:

 

struct s
{
	int a : 3;
	int b : 4;
	int c : 5;
};

要在结构体成员变量后面加上冒号,并且写上他所要占的位的个数,打个比方,int a:3表示他所占的位数是3,其余成员也是相同道理。而问题来了,位段位段,其中的位是什么意思,这个位其实是二进制位,然后还有一个要注意点的是,位段只能表示整数家族类型的,不能表示浮点型。那么,又来问题了,他所占的大小到底是多少呢?3,4,5这个加起来才是一个字节超几个比特位,而且还没有吧这两个字节沾满,很简单,首先他的大小就是4个字节,我们打印出来看看

 为什么是4个字节呢?因为int类型占用4个字节内存空间,而位段在开辟的时候,是以4(int)或1(char)来开辟空间的,因为3,4,5加起来就是一个字节过几个比特位,也就是两个字节,还没有吧这两个字节占完,所以编译器一下直接给你开辟4个字节的空间。所以此时的大小就是4.而运用位段时应该要注意位段的跨平台问题。

3.枚举

枚举的关键字是enum,下面举个列子:

enum u
{
	RED,
	BLACK,
	BLUE
};

以上就是枚举的类型,他的成员叫做是枚举常量,是有数值的,他的数值是从第一个成员开始,往后的每个成员都是递增1,而第一个成员是0,下面是打印结果:

enum u
{
	RED,
	BLACK,
	BLUE
};
int main()
{
	printf("%d ", RED);
	printf("%d ", BLACK);
	printf("%d ", BLUE);
	return 0;
}

而枚举需要注意的是,他在运行的时候是会进行类型检查的,与宏不同。比宏更加的严谨。 

4.联合体

相比于其余的几个来说,个人感觉联合体与结构体是最像的。因为联合体中也有对齐问题,也是其总体所占大小要是其最大对齐数的整数倍。唯一不同的就是他们的成员公用一块内存空间。下面来看看这个例子:

union u
{
	char arr[7];
	int i;
};
int main()
{
	union u a;
	a.i = 0;
	printf("%d", sizeof(a));
	return 0;
}

调试:

 

在没给i 赋初前,我们可以看到的是数组和i都是乱值,再赋完初值后,可以看到数组的前四个字节都是'\0'也就是0,所以,这个很好的证明了他们共用了一块内存空间。而这个联合体中,最大的占用字节数最多的是数组,占用了7个字节,占用了偏移量为0-6的地方,又因为这个联合体的最大对齐数是4,而6不是对大对齐数的整数倍,所以浪费空间,所以最后的总大小是8。打印结果:

 

总结,其实还是主要学会结构体,因为位段,枚举,联合体其实还是和结构体很类似,像位段,联合体,其实调试一下就知道他的内存分布了,但是一定要知道他们的关键字 ,最后,如果此篇内容对你有用的话就点一下赞吧!!谢谢支持!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值