【自定义类型引领视觉盛宴】(中)

简介: 【自定义类型引领视觉盛宴】

【自定义类型引领视觉盛宴】(上):https://developer.aliyun.com/article/1424800


再来练习一个


#include<stdio.h>
#include<stddef.h>
struct S1
{
  int i;
  char c1;
  char c2;
};
int main()
{
  //offsetof可以计算结构体成员相较于结构体起始位置的偏移量
  printf("%d\n", offsetof(struct S1, i));
  printf("%d\n", offsetof(struct S1, c1));
  printf("%d\n", offsetof(struct S1, c2));
  return 0;
}


代码图解:



验证:



结构体嵌套问题的字节大小求解


#include<stdio.h>
//练习3-结构体嵌套问题
struct S3
{
  double d;
  char c;
  int i;
};
struct S4
{
  char c1;
  struct S3 s3;
  double d;
};
int main()
{
  printf("%d\n", sizeof(struct S4));
  return 0;
}


代码图解:



验证:



为什么存在内存对齐?


1. 平台原因(移植原因):

       不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2. 性能原因:

       数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。


总体来说: 结构体的内存对齐是拿空间来换取时间的做法。


那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到: 让占用空间小的成员尽量集中在一起。


//例如:
struct S1
{
  char c1;
  int i;
  char c2;
};//12字节
struct S2
{
  char c1;
  char c2;
  int i;
};//8字节


S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别。


1.7 修改默认对齐数


之前我们见过了 #pragma 这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数。


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


运行结果:



1.8 结构体传参


#include <stdio.h>
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);
  printf("%d\n", ps->num);
}
int main()
{
  print1(s);  //传结构体
  print2(&s); //传地址
  return 0;
}


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


       print2更好,因为函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。


2. 位段


2.1 什么是位段



  • data_type:表示位段的数据类型。通常可以是整数类型(例如int、char、unsigned int等),也可以是自定义的枚举类型等。
  • member_name:是位段的成员名,用于访问和操作该位段。
  • number_of_bits:是指定该位段所占用的位数。这决定了位段可以表示的最大值范围。通常情况下,位段的位数不能超过其数据类型所能表示的位数。


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


  1. 位段的成员必须是 int、unsigned int signed int
  2. 位段的成员名后边有一个冒号和一个数字
struct A
{
  int _a : 2;
  int _b : 5;
  int _c : 10;
  int _d : 30;
};


A就是一个位段类型。 那位段A的大小是多少?


printf("%d\n", sizeof(struct A));


运行结果:



解释:


       总共需要2个整型(int)来存储结构体struct A的位段成员。而一个整型通常占用4个字节(32位),所以结构体struct A的大小为8个字节。


2.2 位段的内存分配


  1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
  2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
//一个例子
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;
}


空间是如何开辟的?



2.3 位段的跨平台问题


  1. int 位段被当成有符号数还是无符号数是不确定的。
  2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。


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


位段的优点:


       位段允许将多个小的数据成员按位进行存储,从而节省内存空间。在某些嵌入式系统或资源受限的环境中,使用位段可以显著减小数据结构的内存占用。


【自定义类型引领视觉盛宴】(下):https://developer.aliyun.com/article/1424807

相关文章
|
11月前
|
SQL 分布式计算 Serverless
EMR Serverless Spark:一站式全托管湖仓分析利器
本文根据2024云栖大会阿里云 EMR 团队负责人李钰(绝顶) 演讲实录整理而成
545 58
|
前端开发 JavaScript 小程序
Docker实战 | 第三篇:Docker安装Nginx,实现基于vue-element-admin框架构建的项目线上部署
Docker实战 | 第三篇:Docker安装Nginx,实现基于vue-element-admin框架构建的项目线上部署
|
消息中间件 运维 Kubernetes
工作中用Go: Go中异步任务怎么写
工作中用Go: Go中异步任务怎么写
3554 0
工作中用Go: Go中异步任务怎么写
|
机器学习/深度学习 计算机视觉
YOLOv8改进 | 融合改进篇 | CCFM + Dyhead完美融合突破极限涨点 (全网独家首发)
YOLOv8改进 | 融合改进篇 | CCFM + Dyhead完美融合突破极限涨点 (全网独家首发)
648 2
|
前端开发 JavaScript Java
springboot+vue考研资料分享系统
本考研资料分享系统设计目标是实现考研资料的信息化管理,提高管理效率,使得考研资料交流工作规范化、科学化、高效化。本文研究的考研资料分享系统基于Springboot架构,采用JSP技术、JAVA编程语言和MYSQL数据库设计开发。通过本系统,实现了管理员和用户两个角色的功能,能够有效提高考研资料交流诊断效率。本系统经过测试,运行效果稳定,操作方便、快捷,是一个功能全面、实用性好、安全性高,并具有良好的可扩展性、可维护性的考研资料分享系统。论文首先阐述了考研资料分享系统的开发,并对该系统进行了较详细的需求分析,探讨了考研资料分享系统的功能需求、业务流程、系统结构和数据库设计等方面的问题。望能利用先
572 0
|
物联网 API
设备端和服务端检测设备是否在线的方法
使用物联网时,有时设备端和服务端都需要检测设备是否在线。
1697 0
Halcon数据类型转换系列(1)图像image、区域region和轮廓xld的相互转换(★firecat推荐★)
Halcon数据类型转换系列(1)图像image、区域region和轮廓xld的相互转换(★firecat推荐★)
1626 0
|
存储 算法 测试技术
《算法笔记知识点记录》第二章——快速入门4[结构体、输入输出、复杂度和黑盒测试](2)
《算法笔记知识点记录》第二章——快速入门4[结构体、输入输出、复杂度和黑盒测试](2)
《算法笔记知识点记录》第二章——快速入门4[结构体、输入输出、复杂度和黑盒测试](2)
|
XML 前端开发 JavaScript
ajax简介(异步与同步)|学习笔记
快速学习ajax简介(异步与同步)
|
SQL 存储 Oracle
搭建婚恋app源码,使用关系型数据库合适吗?
搭建婚恋app源码,使用关系型数据库合适吗?