自定义类型知识详解(结构体,位段,枚举,联合体)

简介: 结构体是一些值的集合,这些值可以是不同类型的变量,被称为成员变量。

结构体

       定义,初始化,自引用

1:结构体的定义:

结构体是一些值的集合,这些值可以是不同类型的变量,被称为成员变量。

2:初始化:

三种初始化方式,被注释掉的代码只有在支持C99的编译器下才可以使用,他是乱序初始化,我们常用的是顺序初始化。

#include <stdio.h>
struct Student
{
  char name[8];
  int age;
  char sex[4];
}a = {"haha",4,"nan"};           //第一种
int main()
{
  struct Student c = { "gaga",6,"?" };   //第二种
  //struct Student b = { .age = 5, .name = "hehe", .sex = "nu" };   //第三种
  return 0;
}


这里还有一种特殊的声明方式:

a02e5756794942bc8f7cccb86135c6d9.png

这样声明的话只能在这里进行初始化,因为他没有名字,后面再想使用这个结构体,没有名字就无法创建该类型变量。


3:结构体的自引用:


这是错误用例,如果这样写的话,那么sizeof(struct Student)大小是多少呢?这样是算不出来的。

8b838fce16944e08aa4eb481f78e03df.png


接下来我们看正确用例:


这样,就是一个指针,指向这个结构体类型,就不会出现上面无限套娃的情况,再往后面加其实就是一个链表了。

377093a971e64cac8d296473050e0ddd.png


再看重命名后的错误用例:

53ce8cac48fc4111ac90fcae51ff737d.png


Stu前面的代码(typedef是重命名,不算在类型里)都是这个结构体类型,也就是说Stu在结构体里是未定义的,然后去使用Stu,这是错误的,改正:


86eae6ed3cb342aabdd8d00b91d06803.png

  内存对齐,修改默认对齐数

这里我们将说到结构体的大小计算,涉及到结构体的内存对齐。


我们先看一下这个结构体的大小,各位也可以先计算一下,看看结果是否正确。


eaf4a64a121847ffbcfcb25e840d6798.png

正确答案是:12个字节,你算对了吗?


结构体对齐规则:

       1:第一个成员变量在与结构体偏移量为0的位置。

5052d4d6868c486f91e21a2fe6fb9d5c.png

2:每个成员变量要对齐到他们各自的对齐数的整数倍处,也就是说偏移量是其对齐数的整数倍,起始偏移量为0,对齐数的大小为其sizeof的大小与默认对齐数比较后取小者。

3:每个编译器都有默认对齐数,VS为8个字节,计算结构体总大小时要看其最大对齐数,取成员变量中最大的对齐数,在每个成员变量各自对齐后,结构体所占内存总大小是将总和补到最大对齐数的整数倍。

4:如果嵌套了结构体,则嵌套的结构体的最大对齐数为其自身的最大对齐数,对齐到自身最大对齐数的整数倍处。


接下来我们来计算这个案例


char ch 占一个字节,VS默认对齐数为8,取小,对齐数为1, 放在开头,int a占4个字节,比8小,对齐数取4,4偏移量是4的倍数,从4位置开始分配四个字节的内存空间,short同理,8是2的整数倍,从该处分配内存空间。


结构体中成员变量的对齐数中最大为4,与默认对齐数8相比取4,最大对齐数为4,总大小为4的倍数,则取12个字节。图中占用字节为7个字节,浪费5个字节,但这是有意义的

dc9caec8c8644cf5bff05099a51df269.png

内存对齐的意义:

1:平台的移植性:不是每个平台都能访问任意位置的地址上的任意数据。

2:性能原因:

6cc4806ec47a4391b57fa423e049e59a.png

总的来说,结构体内存对齐就是用空间换取时间的做法


       传参:

结构体传参最好传指针,如果传值,实参的临时拷贝对栈区的压力会增大。

#include <stdio.h>
#include <string.h>
typedef struct T
{
  int a;
  char b;
}T;
void Test(T* stu)
{
  printf("haha:%d", stu->a);
}
int main()
{
  T stu;
  memset(&stu, 0, sizeof(T));
  Test(&stu);
  return 0;
}

位段

1:位段成员必须是int ,signed int,unsigned int(char也可以)

2:位段成员名后面有一个冒号和数字(分配的bit位)

8e26389dd07a43b980d329b25fb32c43.png

A就是一个位段类型。


       位段内存问题

位段涉及很多问题,比如读取数据的方向,空间不足时数据存部分还是不存。

位段的空间开辟是按照开辟四个字节(int),或一个字节(char)的方式

5dcf79ba11824fc9a4b195e32a94e72b.png

      跨平台及其应用问题

a1d1eb05c0dd4e0188c5b461bbf29c9c.png

image.png

枚举

       定义,初始化

enum A
{
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday
};

使用enum创建枚举类型,从第一个枚举常量开始,若不给定值,默认为0,后面的枚举常量依次加1,我们看结果:

image.png

当然,我们也可以给枚举常量赋初值:

image.png

 实战举例使用及其优点

2c1d8665ec464069840c6052e8017d18.png

只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。

a6208bc20e694d34af6c9091927abfa5.png

当然,硬要强制转换也是可以的,不推荐。


一般来说我们也不这么用,真正要用是在switch语句中使用,每一个case后的常量换成枚举常量。

比如:

case 0:我们可以换成case Add:(假设Add是枚举常量的第一个)


这样我们看起来就会方便一些,不会说一看0,不清楚这是做什么的。


联合体

       联合体定义:

一种特殊的自定义类型,接下来看声明:

dca234551aac4dfca1b88797bf9c1b8d.png

      特点:

所有成员共用同一块空间,他们的起始地址都相同:

c72a291258da45cc967b4ec45982c5e7.png

一个union联合体的大小,至少是最大成员的大小。


       大小计算问题

整体大小也要对齐到最大对齐数的整数倍,上面举例的联合体大小为4个字节。

目录
相关文章
|
网络协议 Ubuntu 网络安全
如何搭建 Jump Server
搭建 Jump Server(跳板服务器)是为了安全地管理远程服务器,通常通过 SSH 连接。
398 0
|
Web App开发 运维 安全
SSL/TLS证书1年有效期新规已至,被“证书过期”支配的恐惧又增加了!
9月1日起,两年期公共SSL/TLS证书正式告别了行业,在三大浏览器(Apple Safari、 Google Chrome、Mozilla Firefox)的推动下,SSL/TLS证书最长有效期变更为13个月,同时,全球各大证书权威签发机构已停止签发有效期超过1年(398天)的SSL证书。
SSL/TLS证书1年有效期新规已至,被“证书过期”支配的恐惧又增加了!
|
NoSQL 索引 MongoDB
利用MongoDB的SplitVector命令实现并发数据迁移
数据迁移是数据库运维中一个很常见的场景。数据迁移分为全量和增量。为了追求速度,通常我们会采用并发的方式对数据进行全量迁移。在全量导出数据时,通常都会选择做到记录级的并发,因此通常会涉及到对需要导出的某个表(集合)按照并发度进行切分(分区)的过程。现有常用做法是通过若干个skip加limit来找到一些分区点,然后就可以并发同时导出多个分区。事实上MongoDB还有一个SplitVector命令特别适合用来做集合的分区。本文将介绍一下如何利用这个命令来对集合做分区,实现并发数据迁移。
6883 0
|
11月前
|
Java 程序员 测试技术
项目构建工具
项目构建工具
219 1
|
11月前
|
Java 关系型数据库 MySQL
数据库的连接用Java
本文介绍了如何使用Java连接MySQL数据库,包括注册JDBC驱动、创建数据库连接URL、设置数据库用户和密码、建立连接以及关闭连接的完整代码示例。
304 0
数据库的连接用Java
|
运维 算法 计算机视觉
【Qt&OpenCV 图像的模板匹配 matchTemplate/minMaxLoc】
【Qt&OpenCV 图像的模板匹配 matchTemplate/minMaxLoc】
288 1
|
存储 开发框架 安全
【C++ 线程】深入理解C++线程管理:从对象生命周期到线程安全
【C++ 线程】深入理解C++线程管理:从对象生命周期到线程安全
907 0
|
缓存 开发工具 数据安全/隐私保护
git-学习git,这一篇就足够了(初学者视角实战教程)
git-学习git,这一篇就足够了(初学者视角实战教程)
329 0
|
Android开发
Android 实现视图文本TextView的展开与收缩功能
Android 实现视图文本TextView的展开与收缩功能
528 0
ROW_NUMBER() OVER()函数用法详解 (分组排序 例子多)
ROW_NUMBER() OVER()函数用法详解 (分组排序 例子多)
211 0