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

c语言中结构体传参和实现位段

结构体传参

有两种方法:

#include<stdio.h>
struct S
{int data[1000];int num;
};
//结构体传参 
void print1(struct S s)
{printf("%d\n",s.num);
}
//结构体地址传参 
void print2(struct S *ps)
{printf("%d\n",ps->num);
}int main()
{print1(s);print2(&s);return 0;
}

以上两种方法,哪一个函数更好一点?

答案是:首选print2函数.

原因 : 函数传参的时候,参数有时候需要压栈,会有时间和空间上的系统开销.

如果传递一个结构体对象的时候 , 结构体过大 , 参数压栈的系统开销比较大 , 所以会导致性能的下降.

结论就是: 结构体传参的时候,要传结构体的地址.

结构体实现位段

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

1,位段的成员必须是  int  ,  unsigned  int  或  signed  int

2,位段的成员名后面有一个冒号和一个数字

比如:

struct A
{int _a:2;int _b:5;int _c:10;int _d:30;} ;
int main()
{
printf("%zd\n",sizeof(struct A));//结构体A占用的内存大小为8
return 0;
}
struct S
{int _a;int _b;int _c;int _d;} ;
int main()
{
printf("%zd\n",sizeof(struct S));//结构体S占用的内存为16
return 0;
}

位段的内存分配

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

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

例如:

#include<stdio.h>
struct S
{char a:3;char b:4;char c:5;char d:6;};int main(){struct S s;printf("%zd\n",sizeof(struct S));//3return 0;}

内存判断方法:

1.给定了空间后,在空间内部是从左到右使用,还是从右到左,这个是不确定的

假设 : 是从右到左

2.当下剩下的空间不足以存放下一个成员的时候,空间是浪费还是使用,不确定。

假设:浪费

所以,根据以上的推断

a占用3个bit ,b占用4个bit,所以当开辟一个字节的时候,其存储方式就是如下

因为从右到左进行存储:不足存放的时候,浪费,所以从新开辟一个新的空间

而c占用5个bit:,次空间剩下一个不够进行存放,所以从新开辟一个放c

而此时上下三个,而d占用四个bit,所以不够,在从新开辟一个空间,进行存储d

综上所述:一共开辟了3次空间,每一个都是8个bit,所以一共是三个字节

位段的跨平台问题:

1.int被当作有符号数还是无符号数是不确定的

2.位段中最大位数的数目不能确定,(16位机器最大16,32位机器最大32,写成27,在16位会出现问题的)

3.位段中的成员在内存中从左向右进行分配,还是从右向左,标准尚未定义。

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

总结:跟结构体相比,位段可以达到同样的效果,斌且可以更好的节省空间,但是又跨平台的问题存在。

位段使用的注意事项:

位段的几个成员共有同一个字节,这样有些成员的起始位置并不是每个字节的起始位置,那么这些位置处是没有地址的,内存中每个字节分配一个地址,一个字节内部的bit位是没有地址的

所以不能对位段的成员使用&操作符,这样就不能使用scanf直接给位段的成员进行输入,只能是先输入放在一个变量中,然后赋值给位段的成员。

例如:这是错误的

#include<stdio.h>
struct A
{int _a:2;int _b:3;
};
int main()
{struct A sa = {0};scanf("%d",&sa._b);//这是错误的 return 0;
}

正确的:

#include<stdio.h>
struct A
{int _a:2;int _b:3;
};
int main()
{//正确的示范 int b=0;scanf("%d",&b);sa._b = b;return 0;
}


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

相关文章:

  • 活着就好20241030
  • Vue学习笔记(三)
  • React 分装webSocket
  • 大数据新视界 -- 大数据大厂之大数据重塑影视娱乐产业的未来(4 - 3)
  • Windows安装PM2 注意事项与错误查改
  • C++基于opencv的视频质量检测--遮挡检测
  • unseping攻防世界
  • 百度二面算法:合法的括号字符串(贪心解法)
  • 【机器学习】环境搭建及Sklearn鸢尾花数据集
  • Python | Leetcode Python题解之第519题随机翻转矩阵
  • Python中的切片是什么,它有什么用处?
  • 25_DNS:域名系统详解
  • C++ | Leetcode C++题解之第519题随机翻转矩阵
  • windows 驱动实例分析系列: NDIS 6.0的Filter 驱动改造(四)
  • Java | Leetcode Java题解之第520题检测大写字母
  • Linux(一)
  • 从0开始搭建一个生产级SpringBoot2.0.X项目(五)使用 validation 验证参数
  • C++核心编程和桌面应用开发 第十七天(set和multiset容器 pair map和multimap容器)
  • Json库和文件操作
  • Cargo 的工作机制
  • 一道巧妙的卡特兰数建模
  • 聊聊解构的那些事
  • 本篇文章来介绍下dockerfile
  • LeetCode 热题 100 回顾2
  • Golang | Leetcode Golang题解之第519题随机翻转矩阵
  • 速盾:海外高防CDN有哪些优势?