结构体全解,适合初学者的一条龙深度讲解(附手绘图详解)下

简介: 结构体全解,适合初学者的一条龙深度讲解(附手绘图详解)

2.1修改默认对齐数


我们可以通过#pragma pack()指令来修改默认对齐数。


#include <stdio.h>
#pragma pack(1)
//设置默认对齐数为1
struct S1
{
  char c1;
  int i;
  char c2;
};
int main()
{
  //输出的结果是什么?
  printf("%d\n", sizeof(struct S1));
  return 0;
}


968045478fc11a763247b86708e8801d_01ec18b9e3da48b8a60163a9b0185089.png


可以看到,答案不再是12,默认对齐数确实被修改了。


想要取消的话就引入一个空指令。


#include <stdio.h>
#pragma pack(1)//设置默认对齐数为1
#pragma pack()//取消设置的默认对齐数,还原为默认
struct S1
{
  char c1;
  int i;
  char c2;
};
int main()
{
  //输出的结果是什么?
  printf("%d\n", sizeof(struct S1));
  return 0;
}


a4973c80bc93d1b85c6291017aca52bb_dcdae90c9721485bba16108f55ea6530.png


2.2 结构体传参


下面print1和print2那个比较好?


struct S
{
 int data[1000];
 int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
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;
}

上面的 print1 和 print2 函数哪个好些?

答案是:首选print2函数。

原因:

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。

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

所以结构体传参数时,要传结构体的地址。


3.1位段


结构体讲完就得讲讲结构体实现 位段 的能力。

struct A
{
 int _a:2;
 int _b:5;
 int _c:10;
 int _d:30;
};

A就是一个位段的类型,位段可以控制所给的空间大小,达到节省空间的目的。


它所占空间是多大?


#include <stdio.h>
struct A
{
  int _a : 2;
  int _b : 5;
  int _c : 10;
  int _d : 30;
};
int main()
{
  printf("%d\n", sizeof(struct A));
  return 0;
}


e567e08aa3df4cd5a68b1cfeb9cd141b_144a3809ce294084ad85275b813a0dd4.png


它占了8*8=64个比特位。


从16个字节优化到8个字节,位段的功能可以说是十分强大。


3.2 位段的内存分配


1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型

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

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

#include <stdio.h>
//一个例子
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;
}


首先做一个假设,假设内存中的比特位是由右向左使用的。

一个字节内部,剩余的比特位不够使用时,直接浪费掉。


14da58387aaba67e5f185188dfd193ba_8b4225b5319f474b8412cefbff62afa3.png


我们猜想是这个样子。


转换成16进制为:


62  03  04


我们来调试看看:


2f717c4b63d0f72f57b1bfa54d44a952_362b666259d04c64be1e470baf7d2359.png


我们的猜想是正确的!


3.3 位段的跨平台问题


1. int 位段被当成有符号数还是无符号数是不确定的。

2. 位段中最大位的数目不能确定。( 16 位机器最大 16 , 32 位机器最大 32 ,写成 27 ,在 16 位机

器会出问题。

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

4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是

舍弃剩余的位还是利用,这是不确定的。

总结:

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


5afd1174262572c8492490f4c580e7b1_304e31657dd24eee9c48b710a07b8d3e.png


这篇博客旨在总结我自己阶段性的学习,要是能帮助到大家,那可真是三生有幸!😀如果觉得我写的不错的话还请点个赞和关注哦~我会持续输出编程的知识的!🌞🌞🌞  


相关文章
|
Java
编程中最难的就是命名?这几招教你快速上手(4)
编程中最难的就是命名?这几招教你快速上手
80 0
编程中最难的就是命名?这几招教你快速上手(4)
|
5月前
|
存储 Java 数据处理
启航Java编程:基础三部曲-第二部
启航Java编程:基础三部曲-第二部 Java语法全接触:变量、数据类型与运算符详解
72 1
|
6月前
|
机器学习/深度学习 自然语言处理 API
有一点python基础,想玩大模型,不知从何入手。快速入门。
有一点python基础,想玩大模型,不知从何入手。快速入门。
678 0
编程中最难的就是命名?这几招教你快速上手(2)
编程中最难的就是命名?这几招教你快速上手
48 0
编程中最难的就是命名?这几招教你快速上手(2)
|
Java 程序员 编译器
编程中最难的就是命名?这几招教你快速上手(1)
编程中最难的就是命名?这几招教你快速上手(1)
79 0
编程中最难的就是命名?这几招教你快速上手(1)
|
6月前
第七章:函数实训
第七章:函数实训
40 0
|
关系型数据库
编程中最难的就是命名?这几招教你快速上手(3)
编程中最难的就是命名?这几招教你快速上手
55 0
|
Java 关系型数据库 程序员
编程中最难的就是命名?这几招教你快速上手
编程中最难的就是命名?这几招教你快速上手
724 11
|
存储 编译器 C语言
结构体全解,适合初学者的一条龙深度讲解(附手绘图详解)上
结构体全解,适合初学者的一条龙深度讲解(附手绘图详解)
104 0
|
XML 前端开发 JavaScript
没有一个顺手的流程绘制工具?好吧,自己动手,丰衣足食
没有一个顺手的流程绘制工具?好吧,自己动手,丰衣足食