目录
今天接着我们继续自定义类型结构体。🙂🙂
在我们初阶结构体我们学习过结构体传参的知识。
关于下面代码:
- #include
- struct S
- {
- int data[1000];
- int num;
- };
- //结构体传参
- //栈区形参开辟一块空间,实参开辟一块空间,很浪费
- void print1(struct S s)//形参
- {
- printf("%d\n", s.num);
- }
- //结构体地址传参
- //压栈的时候只用开辟四个字节的空间,效率更高
- void print2(const struct S* ps)//不安全 -> const 安全
- {
- printf("%d\n", ps->num);
- }
- int main()
- {
- struct S s = { {1,2,3,4}, 1000 };//实参
- print1(s); //传结构体 传值调用
- print2(&s); //传地址 传址调用
- return 0;
- }
上面的print1和print2那个好?明显,print2。
- 函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
- 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
- 如果觉得指针不安全,怕改变原数据,请加上const。
- 结构体传参数的时候,要传结构体的地址。(选传址调用)
在上一篇博文我们讲完了结构,这篇我们来谈谈位段。结构会为了效率浪费空间,位段出现就是为了节省空间。
位段的声明和结构是类似的,有两个不同:
- //位段
- struct A
- {
- int _a : 2;
- int _b : 5;
- int _c : 10;
- int _d : 30;
- };
- //结构
- struct A
- {
- int _a;
- int _b;
- int _c;
- int _d;
- };

- A就是一个位段类型_位指的是二进制位
- _a占用2个比特位
- _b占用5个比特位
- _c占用10个比特位
- _d占用30个比特位
一个结构体的某一些成员,它对内存的需求,只是占了给它分配内存空间的一部分吗,用不完。那么此刻我们就可以使用位段,去保证效率的同时节省空间。
- #include
- struct A
- {
- int _a : 2;
- int _b : 5;
- int _c : 10;
- int _d : 30;
- };
- int main()
- {
- printf("%d", sizeof(struct A));
- return 0;
- }

是否和你预期的一样呢??
- 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型。
- 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
- 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
不确定因素:位段的跨平台问题。
到底是怎么开辟的呢?简单来说,就是依次开辟。例如先开辟一个字节空间(8个比特位),不够的话再开辟1个字节的空间,依次下去...
那不同编译器有所差别,又有很多不确定因素。即便这样,我们还是可以探究一下在VS上到底是怎么使用的?
- //一个例子
- struct S
- {
- char a:3;
- char b:4;
- char c:5;
- char d:4;
- };
- struct S s = {0};
- s.a = 10;
- s.b = 12;
- s.c = 3;
- s.d = 4;
- //空间是如何开辟的?
我们猜测在VS编译器上:
- 内存分配是从低地址到高地址
- 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的。

我们验证发现,果然等于3。 
有人说可能是巧合,或者从高到低地址也是这样的。那我们调试验证一下。

调试,&s之后,在内存窗口。


位段应用在网络工程等方面。有兴趣可以下去了解一下

✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!
下篇博文我们继续自定义类型&枚举&联合。
代码------→【gitee:唐棣棣 (TSQXG) - Gitee.com】
联系------→【邮箱:2784139418@qq.com】