• C语言之自定义类型_结构体篇(2)


    目录

    结构体传参

    结构体实现位段(位段的填充&可移植性)

    什么是位段

    位段的大小计算 

    位段的内存分配

    位段的跨平台问题

    位段的应用


    今天接着我们继续自定义类型结构体。🙂🙂

    结构体传参

    在我们初阶结构体我们学习过结构体传参的知识。

    关于下面代码:

    1. #include
    2. struct S
    3. {
    4. int data[1000];
    5. int num;
    6. };
    7. //结构体传参
    8. //栈区形参开辟一块空间,实参开辟一块空间,很浪费
    9. void print1(struct S s)//形参
    10. {
    11. printf("%d\n", s.num);
    12. }
    13. //结构体地址传参
    14. //压栈的时候只用开辟四个字节的空间,效率更高
    15. void print2(const struct S* ps)//不安全 -> const 安全
    16. {
    17. printf("%d\n", ps->num);
    18. }
    19. int main()
    20. {
    21. struct S s = { {1,2,3,4}, 1000 };//实参
    22. print1(s); //传结构体 传值调用
    23. print2(&s); //传地址 传址调用
    24. return 0;
    25. }

     上面的print1和print2那个好?明显,print2。

    • 函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
    • 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
    • 如果觉得指针不安全,怕改变原数据,请加上const。 
    • 结构体传参数的时候,要传结构体的地址。(选传址调用)

    结构体实现位段(位段的填充&可移植性)

    在上一篇博文我们讲完了结构,这篇我们来谈谈位段。结构会为了效率浪费空间,位段出现就是为了节省空间。

    什么是位段

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

    • 位段的成员必须是int unsigned int signed int
    • C99之后,也可以是其他类型,但是基本上都是 int char 整型家族🆗
    • 位段的成员名后边右一个冒号和一个数字。
    1. //位段
    2. struct A
    3. {
    4. int _a : 2;
    5. int _b : 5;
    6. int _c : 10;
    7. int _d : 30;
    8. };
    9. //结构
    10. struct A
    11. {
    12. int _a;
    13. int _b;
    14. int _c;
    15. int _d;
    16. };

    • A就是一个位段类型_位指的是二进制位
    • _a占用2个比特位
    • _b占用5个比特位
    • _c占用10个比特位
    • _d占用30个比特位 

     一个结构体的某一些成员,它对内存的需求,只是占了给它分配内存空间的一部分吗,用不完。那么此刻我们就可以使用位段,去保证效率的同时节省空间。

    位段的大小计算 

    1. #include
    2. struct A
    3. {
    4. int _a : 2;
    5. int _b : 5;
    6. int _c : 10;
    7. int _d : 30;
    8. };
    9. int main()
    10. {
    11. printf("%d", sizeof(struct A));
    12. return 0;
    13. }

    是否和你预期的一样呢?? 

    位段的内存分配

    • 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型。
    • 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
    • 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

    不确定因素:位段的跨平台问题

    到底是怎么开辟的呢?简单来说,就是依次开辟。例如先开辟一个字节空间(8个比特位),不够的话再开辟1个字节的空间,依次下去...

    那不同编译器有所差别,又有很多不确定因素。即便这样,我们还是可以探究一下在VS上到底是怎么使用的?

    1. //一个例子
    2. struct S
    3. {
    4. char a:3;
    5. char b:4;
    6. char c:5;
    7. char d:4;
    8. };
    9. struct S s = {0};
    10. s.a = 10;
    11. s.b = 12;
    12. s.c = 3;
    13. s.d = 4;
    14. //空间是如何开辟的?

     我们猜测在VS编译器上:

    • 内存分配是从低地址到高地址
    • 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的。

    我们验证发现,果然等于3。  

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

     

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

    位段的跨平台问题

    • 跟结构体相比,位段可以达到同样的效果,同时可以很好的节省空间,存在跨平台问题。 

    位段的应用

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

    ✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!

    下篇博文我们继续自定义类型&枚举&联合。

    代码------→【gitee:唐棣棣 (TSQXG) - Gitee.com

    联系------→【邮箱:2784139418@qq.com】

  • 相关阅读:
    SpringBoot+Vue项目旅游信息推荐系统【源码开源】
    Git错误解决:如何处理“could not determine hash algorithm“问题
    武忠祥每日一题知识点总结
    【广州华锐互动】AR远程智慧巡检在化工行业中的应用
    错题汇总11 12
    机械设备行业调研:纳米发电机市场规模分析及发展前景预测
    上周热点回顾(9.25-10.1)
    web安全漏洞-SQL注入实验2
    SRM采购管理系统投标管理模块:阳光招采,助力建筑材料企业智慧采购
    VUE学习三:双向绑定指令(v-mode)、组件化开发(全局组件/局部组卷/组件通信)、组件化高级(slot插槽使用)
  • 原文地址:https://blog.csdn.net/m0_74841364/article/details/133610928