当前位置: 首页 > news >正文

64.【C语言】再议结构体(下)

本文衔接第63篇63.【C语言】再议结构体(上)

目录

目录

6.复习

7.修改默认对齐数

8.结构体传参

01.传递非指针参数

02.传递指针参数(传递地址)

03.对比

9.结构体实现位段

01.位段的定义

02.格式

03.例题

答案速查

分析

10.位段跨平台问题

11.位段的应用

12.其他注意事项



6.复习

20.【C语言】初识结构体(重要)

48.【C语言】结构体补充

63.【C语言】再议结构体(上)

7.修改默认对齐数

加一条预处理指令

#pragma pack(对齐数)
struct 结构体标签{成员列表;}变量列表(全局变量);//变量列表可以不写,但;必须有!!!

 在#pragma pack(对齐数)后紧跟着结构体就能指定该结构体的对齐数

建议给1,2的次方数:2,4,8

#include <stdio.h>
#pragma pack(1)
struct s1
{char a;char b;int c;
};
#pragma pack()//恢复默认对齐数int main()
{printf("%zd", sizeof(struct s1));return 0;
}

打印结果为6

8.结构体传参

01.传递非指针参数

#include <stdio.h>
struct s
{int data[1000];int num;
};void sim_print(struct s ss)//结构体传参
{int i = 0; for (i = 0; i < 5; i++){printf("%d ",ss.data[i]);}printf("\nnum = %d\n", ss.num);
}int main()
{struct s s = { { 1, 2, 3, 4, 5 } , 100 }; sim_print(s);return 0;
}

 649fedba905547ce98c30e0799df9aa3.png

f592253b4fb1450b9a35f9439c373d9e.png

02.传递指针参数(传递地址)

#include <stdio.h>
struct s
{int data[1000];int num;
};//结构体传参,*ps表明传递的是指针
void sim_print(struct s *ps)
{int i = 0; for (i = 0; i < 5; i++){printf("%d ",ps->data[i]);}printf("\nnum = %d\n", ps->num);
}int main()
{struct s s = { { 1, 2, 3, 4, 5 } , 100 }; sim_print(&s);//传的是地址return 0;
}

注:结构体成员变量->成员名是结构体特有的写法

03.对比

当结构体成员变量占用较大的内存时, 因为参数要压栈,所以传递指针参数比传递非指针参数要节省空间,传递指针参数不会另外开辟额外的空间

9.结构体实现位段

01.位段的定义

摘自百度百科:

C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”(bit field),利用位段能够用较少的位数存储数据

02.格式

类型 成员变量:数字;

如: int a:5;

03.例题

求下列代码的执行后位段在内存中的数据(在VS2022中测试)

struct S
{char a : 3;char b : 4;char c : 5;char d : 4;
};int main()
{struct S s = { 0 };//注意区分大小写s.a = 10;s.b = 12;s.c = 3;s.d = 4;return 0;
}

答案速查

位段在内存中的数据:62 03 04

分析

因为 以位为单位来指定其成员所占内存长度

前置知识:位段的内存分配

2条规则,1条提醒

1.位段的成员可以是int,unsigned int,signed int,char等类型

2.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的

提醒:位段涉及很多不确定因素,位段不跨平台,注重可移植的程序应该避免使用位段(本文后面会单独讲)

位段的内存分配

1.数据的存储顺序由是编译器而定(C标准没有规定)

2.每次向CPU申请1byte,如果不够则继续申请1byte

3.是否浪费空间取决于编译器(C标准没有规定)

解析

未存储数据时:

8b54a2c5b70741d3a0b31291363bed7c.png

分类讨论:

若按浪费空间处理

由低地址向高地址存储,设数据的二进制的存储顺序为从右向左(VS2022满足此情况)

十进制10==二进制1010 十进制12==二进制1100 十进制3==二进制11 十进制4==二进制100

    char a : 3;-->a占3位,1010会被截断为3位010存储
    char b : 4;-->b占4位,恰好可以存储1100
    char c : 5;-->c占5位,11占2位,因此补前导零存储为00011
    char d : 4;-->d占4位,100占3位,因此补前导零存储为0100

bca644ba52134c04bde9d4f35623ab84.png

 按十六进制拆分:0110 0010 0000 0011 0000 0100-->62 03 04

位段的空间以4个字节(int)或者1个字节(char)的方式来开辟的,a,b,c,d的类型全为char,因此不用改动为62 03 04 00

验证

VS2022+x64+debug环境下,VS2022调试,F11逐语句

打开内存窗口,输入&s(小写的s)

1c00e7ec857d4297977fbc51bd1b0aa2.pngde85388a6fd34fba86f07a8793c38583.png

b340dfd98b364e48a8e49e951e5cce55.png

03d67f85d9544c539904305d7925596c.png

176711e990a04735b45453832a1434b8.png

10.位段跨平台问题

1.int 位段被当成有符号数还是无符号数是不确定的(即最高位为1还是0不确定)

2.位段中最大位的数目不能确定

例如:int a : 34;

a为34位,在16位和32位机器均不能存储,但在64位机器可以

3.位段中的成员在内存中的存储顺序为从左向右还是从右向左,C标准尚未定义

4.当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,不确定

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

11.位段的应用

下图是网络协议中IP数据报的格式,可以看到其中很多的属性只需要几个bit位就能描述

这里使用位段能节省了空间,这样网络传输的数据报大小也会较小一些,对网络的畅通是有帮助的。

12.其他注意事项

位段的几个成员共有同一个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处是没有地址的(内存中每个字节分配一个地址,一个字节内部的bit位是没有地址的)
所以不能对位段的成员使用&操作符,这样就不能使用scanf直接给位段的成员输入值,只能是先输入放在一个变量中,然后赋值给位段的成员

int a=0;
scanf("%d",&a);
s.a = a;

http://www.mrgr.cn/news/39623.html

相关文章:

  • 编程题 7-13 日K蜡烛图【PAT】
  • Hadoop搭建及Springboot集成
  • Redis缓存穿透解决方案之一:布隆过滤器与计数型布隆过滤器概述以及两者在Spring中的使用
  • 道可云人工智能元宇宙每日资讯|首届天府人工智能大会在成都举办
  • HashMap原理
  • 方法 WebDriverWait
  • 创客匠人第二期“老蒋面对面”交流会圆满收官!
  • 编程题 7-14 求整数段和【PAT】
  • Gromacs pdbtogro and grotopdb问题
  • 微信广告任务平台 ajax_upload 任意文件上传漏洞
  • Linux之实战命令21:stat应用实例(五十五)
  • 麦克风哪个好,领夹麦什么品牌最好,最新领夹麦克风品牌排行榜
  • 企业微信群发工具:精准营销与高效沟通的新篇章
  • EE trade:试金石怎么辨别真假黄金
  • 2024年华为OD机试真题-找终点-Java-OD统一考试(E卷)
  • 中国测绘科学研究院发布:2015/2020中国337城市优于2米分辨率建成区数据(SHP)
  • 关于手写promise的一点补充
  • 开源软件简介
  • 在java后端发送HTTPClient请求
  • Gelatinous Cube Sphere - Bonus Files 2 - Atavism