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

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

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


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


相关文章
|
6月前
|
存储 缓存 安全
C++数组全解析:从基础知识到高级应用,领略数组的魅力与技巧
C++数组全解析:从基础知识到高级应用,领略数组的魅力与技巧
134 1
|
2月前
|
前端开发 Java 数据库
💡Android开发者必看!掌握这5大框架,轻松打造爆款应用不是梦!🏆
在Android开发领域,框架犹如指路明灯,助力开发者加速应用开发并提升品质。本文将介绍五大必备框架:Retrofit简化网络请求,Room优化数据库访问,MVVM架构提高代码可维护性,Dagger 2管理依赖注入,Jetpack Compose革新UI开发。掌握这些框架,助你在竞争激烈的市场中脱颖而出,打造爆款应用。
329 3
|
3月前
|
图形学 人工智能 C#
从零起步,到亲手实现:一步步教你用Unity引擎搭建出令人惊叹的3D游戏世界,绝不错过的初学者友好型超详细指南 ——兼探索游戏设计奥秘与实践编程技巧的完美结合之旅
【8月更文挑战第31天】本文介绍如何使用Unity引擎从零开始创建简单的3D游戏世界,涵盖游戏对象创建、物理模拟、用户输入处理及动画效果。Unity是一款强大的跨平台游戏开发工具,支持多种编程语言,具有直观编辑器和丰富文档。文章指导读者创建新项目、添加立方体对象、编写移动脚本,并引入基础动画,帮助初学者快速掌握Unity开发核心概念,迈出游戏制作的第一步。
162 1
|
3月前
|
存储 编译器 数据处理
【编程秘籍】解锁C语言数组的奥秘:从零开始,深入浅出,带你领略数组的魅力与实战技巧!
【8月更文挑战第22天】数组是C语言中存储同类型元素的基本结构。本文从定义出发,详述数组声明、初始化与访问。示例展示如何声明如`int numbers[5];`的数组,并通过下标访问元素。初始化可在声明时进行,如`int numbers[] = {1,2,3,4,5};`,编译器自动计算大小。初始化时未指定的元素默认为0。通过循环可遍历数组,数组名视为指向首元素的指针,方便传递给函数。多维数组表示矩阵,如`int matrix[3][4];`。动态数组利用`malloc()`分配内存,需用`free()`释放以避免内存泄漏。掌握这些技巧是高效数据处理的基础。
70 2
|
5月前
|
存储 Java 数据处理
启航Java编程:基础三部曲-第二部
启航Java编程:基础三部曲-第二部 Java语法全接触:变量、数据类型与运算符详解
72 1
|
6月前
|
编译器 API Windows
windows编程基础
windows编程基础
41 0
|
6月前
第七章:函数实训
第七章:函数实训
39 0
|
编译器 程序员 C语言
游戏编程之二 windows编程基础
游戏编程之二 windows编程基础
77 0
|
存储 编译器 C语言
结构体全解,适合初学者的一条龙深度讲解(附手绘图详解)上
结构体全解,适合初学者的一条龙深度讲解(附手绘图详解)
101 0
|
Java C#
【c#入门杂选】-带你熟知c#基础知识点《思维导图》
【c#入门杂选】-带你熟知c#基础知识点《思维导图》
173 0