自定义类型:结构体,枚举,联合(2)

TIPS

1. 类型的定义可以考虑放在头文件里头。
2. 一个汉字存储的时候占两个字节空间
3. 关于结构体变量初始化的一些细节

4. 

关于结构体内存对齐的补充

1.  

2. S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别。 

3. 这两个结构体类型成员都是一模一样的,只是换了顺序而已,但计算大小时完全不一样(成员一模一样)。那么为什么第一个就浪费空间了,而第二个能够节省空间呢?明明它们的结构体成员都是一模一样的,
4. 原因其实很简单,因为第二个结构体把小的成员集中放在一起了,其实两个char类型完全可以放在一起,反正你如果不放在一起的话,那个空间白白浪费掉了,不如在塞进去一个char
5. 所以我们在设计结构体的时候,尽量让那些占用空间小的成员集中在一起,就能更加节省空间,使得空间利用率更高。

6. 当结构体里面的成员是数组的时候,如何对齐与存放呢?就这么去理解,比如说结构体成员char arr[5],其实相当于就是写了五个char类型的结构体成员。我在对齐的时候只看元素的类型,至于几个元素,看成一个一个相同类型的成员就OK了。看元素类型。 

修改默认对齐数 

1. 在VS环境下,默认对齐数是8,但这个8总是合适吗?有时候我需要2或者4......
2. 这个默认对齐数是可以修改的
3. 用#pragma pack()其实可以用来设置我们的默认对齐数。
4. 怎么用呢?
#pragma pack(n)的意思就是我把它的默认对齐数设置为n。
#pragma pack( )给个空格不写数字,就是把自己设置的默认对齐数取消,恢复默认对齐数恢复成8。

5. 默认对齐数会对你计算结构体成员对齐数产生影响,继而对最终的结构体占的总字节数产生影响。算结构体对齐数是取小的那个
6. 如果你#pragma pack(1),把默认对齐数改成1,从此以后就没有对齐了,就是紧挨着放了。
7.   32/64位跟默认对齐数无关,默认对齐数是根据实际需求来的。 

结构体传参 

1. 结构体里面一般成员很多,占的内存空间蛮大的
2. 如果某一天我想把我创建的结构体对象传递给某些函数,我有两选择:我可以把结构体变量本身直接传过去,我在形参部分来个结构体接受一下,然后通过打印形参实际上就是实参里面的数值;我也可以传递结构体的地址,形参用结构体指针接受,然后就是指针有关操作去打印一些数据等等。
3. 到底哪个好?传结构体地址好。函数传参的时候参数是需要压栈的,我要把这个参数给开辟空间,回头我还要从压栈的空间里面去拿形参的数据,如果传递的结构体过大,参数压栈的系统开销会比较大,导致性能下降。
3. 所以未来结构体传参首选传递结构体指针。 

位段(位段式的结构体) 

位段与结构体的关系

1. 位段式结构体同样也是定义结构体只不过是对成员做了一个约束,我在后面加个  :几   就OK了。这种写成结构体的方式,每个成员后面都加个冒号,冒号后面加个数字。这就叫做位段式的结构体,也叫位段。

2. 那什么是位段呢?位段的声明和结构是类似的,位段的成员名后面都有一个冒号与一个数字。我们叫它位段式的结构体=位段

3. 位段能有什么用?还是一样的,结构体能干啥,位段就能干啥。

4. 总而言之,位段就是结构体的子集

5.  位段设计出来它的作用与结构体类似,还是表示一个结构体就是一个结构体只是它的成员加了这种位的形式,我们就叫它位段式的结构体,其也可以表达结构体同样的意思,但能节省空间。

6.  当然有了结构体, 我们为什么还要设计成位段呢?因为有时候我们明确知道结构体的某一个成员不需要占用很大空间,只需要几个bit位就OK了。
7.. 位段式的结构体与结构体的作用与功能一模一样,你什么时候用结构体,就能什么时候用位段,但位段好处就是比结构体更节省空间。只不过比结构体更节省空间罢了。

位段的简单介绍

1. 位段的成员的类型必须是int, unsigned int, signed int(但是实际上,我们通过测试发现,在很多平台上,位段成员的类型是char也没有什么问题,因为char也属于整型家族)。位段的成员可以是int, unsigned int,signed int, char这种属于整型家族的类型。 

2. 而_a与_b与_c与_d都属于位段的成员。位段的成员基本上都是这么同类型的放在一边儿,要么都是char,要么都是int。

3.  那冒号与后面的整数什么意思呢?研究一下,sizeof算一下这个位段式的结构体的大小多少?


4. 为什么呢?如果4个整型的话应该是16个字节啊,它的大小好像比我们这边的纯整型要少一些。

位段的 ":数字 " 的解释

1. 位段(位段式的结构体)中的"位"是二进制位
2. int _a :2    的2表示2个二进制位,说明当前这个成员_a我只占2个二进制位
3. int _b :5    的5表示5个二进制位,说明当前这个成员_b我只占5个二进制位
4. int _c :10    的10表示10个二进制位,说明当前这个成员_c我只占10个二进制位
5. int _d :30    的30表示30个二进制位,说明当前这个成员_d我只占30个二进制位
6. 什么意思呀?事实上我们在定义结构体类型时,其中某些成员取值非常有限,压根不需要太大的变量,有些似乎2个比特位就够用了,如果我对此分配一个整型(32个比特位),我给的空间是不是有点太多了。如果要表达清楚这个成员所表达的意思的话,4或5个比特位就够了,没必要32个比特位。
7. 加上  :  整数  的时候,对于这些成员比如说就不会直接给你开辟一个整型了,大家开始节省空间,占用多少就用多少。一定程度节省了空间。 

位段的内存分配 

1. 位段的空间是按照需要以4个字节(int类型成员)或者1个字节(char成员)不断补给的。

2. 就是说不管最终要用几个比特位

      如果你的成员是int类型,我首先开辟好四个字节(32比特位)

      如果你的成员式char类型,我首先开辟好一个字节(8比特位)

3. 每个位段成员根据冒号后面的标注去占用自己应该占有的内存比特位份额(不同的位段成员之间是无缝对接的,坚决不浪费一个比特位

4.  当现有的空间不能一次性容纳本个位段成员时,再开辟个32/8个比特位,不够再开辟32/8个比特位,不够再开辟,这么一打一打来。一次给你32/8个比特位,一次给你32/8个比特位,用的不够了我在给你32个32个这么一打一打来。  (32还是8个比特位是根据你的位段成员类型来的

5.  

位段的弊端与不确定性

1. 有个问题,当我一个成员发现还有比特位不够的时候,我们知道会新送来32个比特位,我是直接用这些新的呢?还是先占用老的?C语言中没有明确定论,取决于编译器,不同的编译器可能结果不同

2. 比如说成员类型是char,char a :3。好先直接给你来一个字节(8比特位),那么我知道我只需要3比特位,那么是这8个字节从左向右的3个呢?还是从右往左的3个呢?这个C语言标准中也没有说明与规定。

3. 位段涉及很多不确定性。位段不是跨平台的。注重可移植性的程序,避免使用位段。

 

位段的一些小的注意点

1.  注意:32个比特位=4个字节。

2.  位段的成员不能放在其他地方,只能放在结构体里面。

3.  位段本来就是来节省空间的,因此跟结构体内存对齐无关,不然不就矛盾了嘛

4.  截断现象的存在

比如说 位段成员  char a : 3,然后呢我初始化的时候给a赋值1010的二进制补码为1010,可是不对啊,我的a说我只需要用3个比特位了,这时候就会有截断,此时a里面不是10了,而是只存3个比特位010。

 反正就是说多余的给我截断。我说要几个比特位我就占几个比特位,我的其余部分给我截断吧,就算包括1又何妨

位段的应用

1. 数据在网络上传递的时候,比如说a同学与b同学在用微信聊天,网络上只有a,b吗?肯定不是,网络上有成千上万的亿级人在使用微信。
2. 网络上节点不只有a和b,但是如果ab聊天的时候,a给b发了呵呵,难道这个呵呵就直接从a到b去了吗?
3. 不是。实际上,这个呵呵要想从a到b,有非常复杂的分装,需要把数据进行一定的分装。
4. 怎么分装呢?其实看一下ip数据包的分装格式,其实为了传递数据呵呵,将数据进行了上面这样的分装,各种各样的......

5. 其实为了在网络上传输数据,在数据之上又分装了一些数据。这样才能确保我数据在网络上的传
6. 想象一下,版本号我只需要4位,首部长度我只要4位就OK了,服务类型我只需要8位就OK了,总长度我只要16位就OK了,你想象一下,对于这些成员来讲,如果我不讲究的话,空间的浪费会非常严重。
7. 所以怎么办呢?我能不能把这些成员都设置成位段式的成员,这样在一定程度上节省了很多空间。
8. 网络上节省了空间,给我它的效果是什么呢?想象成高速公路,如果在传输数据的时候能够进行很好的设计与压缩,都是一些小的数据包,不会特别大,相当于高速公路上的大客车全都变成了小汽车,这样子的话,网络上的拥堵就没那么容易了。网络状态才会好
9. 所以我们在对数据进行分装的时候,如果能把该省的空间省下来,就可以让我们在网络上的数据不至于太多太大,让网络不至于压力太大。 

VS2019上位段存在的证明

附:

 

再来一个例子:

附:

  

 

  • 15
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

絕知此事要躬行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值