自定义类型

目录

  • 结构体

结构体内存对齐

修改默认对齐数

结构体传参

  • 位段
  • 枚举
  • 联合(共用体)


1.结构体内存对齐

我们先定义一个结构体

S1,S2的大小是多少呢,是一样的吗?如果你认为c1占1个字节,i占4个字节,c2占1个字节,加起来是6个字节,运行起来的话你就发现不是这样,而且S1,S2的大小也不一样。

 

 为什么会这样呢?我们就要研究一个东西:offsetof,它可以计算结构体成员相较于结构体起始位置的偏移量。使用这个宏需要的头文件是stddef.h,我们计算一下每个成员的偏移量:

 如果把它画出来就是这样的:

所以中间为什么会浪费6个字节呢?我们要讲一下结构体内存对齐的规则:

1.结构体的第一个成员永远放在相较于起始位置偏移量为0的地方。

2.从第二个成员开始,往后的每一个成员都要对齐到某个对齐数整数倍处。

对齐数:结构体成员自身的大小和默认对齐数的较小值。

vs上默认对齐数是8。gcc没有默认对齐数,对齐数就是结构体成员自身的大小。

3.结构体的总大小必须是最大对齐数的整数倍。

最大对齐数是所有成员的对齐数的最大值。

所以,解释一下就是这样:

 按照上面的规则,我们看一下S2的大小为什么是8。

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

对于S1,S2这样的例子,我们还能发现:让占用空间小的成员尽量集中在一起会节省空间。

 修改默认对齐数

使用 #pragma 这个预处理指令可以修改默认对齐数

可以看到S1的大小变为了6。

结构体传参

可以看到传值和传址都能达到我们想要的效果,那么哪种方式更好呢?当然是传址。

原因:

  1. 函数传参的时候,参数需要压栈,会有时间和空间上的系统开销。 
  2. 如果传递结构体过大的话,参数压栈的系统开销会比较大,会导致性能的下降。

结论:结构体传参的时候,要传结构体的地址。

2.位段

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

  1. 位段的成员必须是int,unsigend int,sigend int
  2. 位段的成员名后面有一个冒号和一个数字。

 

 A就是一个位段类型。

 

为什么是8?

其实位段的位表示二进制位, 2+5+10+30=47,一共47个字节,开辟8个整形就够了。

位段的内存分配
  1. 位段的成员可以是int,unsigend int,sigend int或char类型。
  2. 位段的空间是按需要以4个字节(int)或1个字节(char)开辟的。
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
位段的跨平台问题
  1. int位段被当成有符号数还是无符号数是不确定的。
  2. 位段中最大位的数目不能确定。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳第一个位段剩余的位时,是舍弃剩余的位还是利用也是不确定的。

总结:

跟结构相比,位段可以达到相同的效果,并且可以很好的节省空间,但是有跨平台的问题存在。

3.枚举

顾名思义就是一一列举,把可能的取值一一列举。

比如:一周有七天,可以一一列举;一年十二个月,也可以一一列举。

枚举常量是有值的,默认从0开始,一次递增1,也可以在声明枚举类型的时候赋初值。

枚举优点:

  1. 增加代码的可读性和可维护性。
  2.  和#define定义的标识符比较枚举有类型检查,更严谨。
  3. 便于调试。
  4. 使用方便,一次可以定义多个常量。

4.联合

联合也是一种特殊的自定义类型。

这种类型定义的变量也包含一系列的成员,特征是这些成员公用一块空间(所以联合体也叫共用体)。

 答案是4,我们来探索一下:

我们先看一下它们的地址

可以看到它们地址都是一样的。

 

联合的特点:

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小。

改i的值就会改c的值。

所以判断大小端我们就可以这样写:

union un
{
	char c;
	int i;
};
int main()
{
	union un u = { 0 };
	u.i = 1;
	if (u.c == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

联合大小的计算 
  • 联合的大小至少是最大成员的大小。
  • 当最大成员大小不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍。

这里就和上面讲的结构体内存对齐类似了,主要注重联合。

例如:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值