【自定义类型】结构体,联合,枚举
在我们学习C语言的时候,有几个自定义类型需要我们掌握,那么我也是根据自己的学习来分享一下自己的理解。希望与大家互相学习,共同进步!
文章目录
- 一:结构体
- 1.1:结构体的基础知识
- 1.2:结构的声明
- 1.3:特殊的声明
- 1.4:结构体的自引用
- 1.5:结构体变量的定义和初始化
- 1.6: 结构体内存对齐
- 1.7:修改默认对齐数
- 1.8:结构体传参
- 二:位段
- 2.1:什么是位段
- 2.2:位段的内存分配
- 2.3:位段的跨平台问题
- 三:枚举
- 3.1:枚举类型的定义
- 3.2:枚举的优点
- 3.3:枚举的使用
- 四:联合(共用体)
- 4.1联合类型的定义
- 4.2 联合的特点
- 4.3:联合大小的计算
一:结构体
1.1:结构体的基础知识
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
1.2:结构的声明
struct tag
{member-list;
}variable-list;//全局变量
例如描述一个学生:
struct Stu
{char name[20];//mingziint age;//nianlinchar sex[2];//xingbiechar id[20];//xuehao
1.3:特殊的声明
在声明结构体的时候。可以不完全的声明。
比如匿名结构体类型。
struct
{int a;char b;float c;
}x;struct
{int a;char b;float c;
}a[20], *p;
上面的两个结构体在声明的时候都省略掉了结构体标签(tag)。
那么问题来了?
p = &x; 合法吗?
警告:编译器会把上面两个声明当成完全不同的两个类型,所以是非法的。
1.4:结构体的自引用
在结构体中包含一个类型为该结构体本身的成员是否可以呢?
struct Node
{int data;struct Node next;
};
这种自引用是不可行的!
下面是正确的自引用方式:
struct Node
{int data;struct Node * next;//结构体的指针类型
};
1.5:结构体变量的定义和初始化
struct Point
{int x;int y;
}p1;//声明类型的同时定义全局变量p1;struct Point p2;//定义结构体变量p2;//初始化:定义变量的同时赋初值、
struct Point p3 = {x, y};
1.6: 结构体内存对齐
我们已经掌握了结构体的基本使用,那么我们现在来讨论结构体的大小
int main()
{struct s1{char c1;int i;char c2;};printf("%d\n", sizeof(struct s1));//12struct s2{char c1;char c2;int i;};printf("%d\n", sizeof(struct s2));//8struct s3{double d;char c;int i;};printf("%d\n", sizeof(struct s3));//16struct s4{char c1;struct s3 S3;int i;};printf("%d\n", sizeof(struct s4));//32system("pause");return 0;
}
如何计算结构体大小?
首先得掌握结构体的对齐规则:
1:第一个成员在与结构体变量偏移量为0的地址处。
2:其他成员变量要对齐到对齐数的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。(VS中默认的值为8)
3:结构体的总大小为最大对齐数的整数倍。
4:如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包括嵌套结构体的对齐数)的整数倍。
为什么要存在内存对齐?
总的来说是:结构体的内存对齐是拿空间换取时间的做法!
那么在设计结构体的时候,我们既要满足对齐,又要节省空间**,那么就让占用空间小的成员尽量集中在一起。**
1.7:修改默认对齐数
之前我们见过了#pragma这个预处理指令,我们再次使用,可以改变我们的默认对齐数。
#pragma pack(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));//12printf("%d\n", sizeof(struct s2));//6system("pause");return 0;
}
结论:结构在对齐方式不合适的时候,我们可以自己更改默认对齐数。
1.8:结构体传参
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);//传结构体地址system("pause");return 0;
}
上面的print1 和print 2 函数哪个好些?
答案是:首选print2 函数
原因:函数传参的时候,参数是需要压栈的,会有时间和空间上的系统开销。如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销较大,导致性能的下降。
结论:结构体传参的时候,要传结构体的地址。
二:位段
2.1:什么是位段
位段的声明和结构是类似的,有两个不同:
- 位段的成员必须是int,unsigned int , 或 signed int, short。
- 位段的成员名后边有一个冒号和一个数字。
比如:
struct A
{int a : 2;int b : 5;int c : 10;int d : 30;
};
int main()
{printf("%d\n", sizeof(struct A));//8system("pause");return 0;
}
A就是一个位段类型,那位段的大小是多少?
理解:位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟,成员后面的数字代表所需要的bit位大小。
2.2:位段的内存分配
- 位段的成员可以是int,unsigned int,signed int,或者 char(属于整型家族)类型。
- 位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟。
- 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
//一个例子
struct S
{char a:3;char b:4;char c:5;char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
空间是如何开辟的?
2.3:位段的跨平台问题
- int 位段被当成有符号数还是无符号数是不确定的。
- 位段中最大位的数目是不能确定的。(16位机器最大16,32位机器最大32)。
- 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
- 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。
总结:跟结构相比,位段可以达到相同的效果,但是可以很好的节省空间,但是又有跨平台的问题存在。
三:枚举
枚举顾名思义就是举例,把可能的取值列举。
3.1:枚举类型的定义
enum Day
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};enum Sex
{MALE,FEMALE,SECRET
};
以上定义的enum Day,enum Sex,都是枚举类型。{}中的内容是枚举类型的可能取值,也叫枚举常量。这些默认取值是有值的。默认从0开始,依次递增1,当然在定义的时候也可以赋初值。
例如:
enum Color
{red = 1,Green = 2,Blue = 4
};
3.2:枚举的优点
我们可以使用#define定义常量,为什么非要使用枚举?
枚举的优点:
- 增加代码的可读性和可维护性。
- 和#define定义的标识符比较,枚举有类型检查,更加严谨。
- 防止了命名污染(封装)。
- 便于调试。
- 使用方便,一次可以定义多个常量。
3.3:枚举的使用
enum Color
{Red = 1,Green = 2,Blue = 4
};int main()
{enum Color clr = Green;system("pause");return 0;
}
注意:只能使用枚举常量给枚举变量赋值,才不会出现类型的差异。
四:联合(共用体)
4.1联合类型的定义
联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列成员,特征是这些成员公用同一块空间。
union Un
{char c;int i;
};
int main()
{union Un un;//联合变量的定义printf("%d\n", sizeof(un));//计算联合变量的大小system("pause");return 0;
}
4.2 联合的特点
联合的成员是共用同一块内存的空间,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
union Un
{char c;int i;
};
int main()
{union Un un;printf("%d\n", &(un.i));printf("%d\n", &(un.c));system("pause");return 0;
}
4.3:联合大小的计算
- 联合的大小至少是最大成员的大小。
- 当最大成员大小不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍。
union Un1
{char c[5];int i;
};
union Un2
{char c[7];int i;
};
int main()
{printf("%d\n", sizeof(union Un1));//大小是8printf("%d\n", sizeof(union Un2));//大小是16system("pause");return 0;
}
我们以上对结构体,位段,联合,枚举这几种自定义类型做出了基础层面上的解读,如果各位看官有收获的话还希望给个三连支持一波,有什么意见或者建议也请评论区指出,谢谢大家!
【自定义类型】结构体,联合,枚举相关推荐
- 【C语言】自定义类型 结构体 枚举 联合
结构体的基础知识 结构体是一些值的集合,这些值称为成员变量.结构体的每个成员可以是不同类型的变量. 结构体的声明 定义一个学生的结构体 struct Stu {char name[20];//名字in ...
- 自定义类型:结构体2.0(初阶+进阶)+位段+枚举+联合
目录 一.结构体
- C语言--自定义类型——结构体
结构体 建立结构体声明 定义结构变量 初始化结构 访问结构体成员 结构的初始化器 结构数组 指向结构的指针 用指针访问成员 向函数传递结构的信息 传递结构成员 传递结构的地址 传递结构 结构和结构指针 ...
- 自定义类型: 结构体,枚举,联合
1.结构体 个人认为结构体和数组特别相似,只不过结构体和数组的区别在于结构体的成员可以是不同类型,而数组成员类型是相同的. (1)结构体的声明 struct tag {成员列表//至 ...
- C语言自定义类型的介绍(结构体,枚举,联合体,位段)
⭐️前面的话⭐️ 大家好!在C语言中,有个叫"自定义类型"玩意,它究竟是什么呢?其实,就是字面意思,可以自己定义的类型就是自定义类型.具体说就是我们熟知的结构体,枚举,位段,联合体 ...
- 关于结构体,枚举,联合的一些知识
关于结构体,枚举,联合的一些知识 首先我们来看一下什么是结构体 通俗来说,结构体便是各种类型的集合. 接下来便是各处所代表的含义了 例如,我们现在来描述一个人. 其中name,age,sex,addr ...
- 一文道破 结构体,枚举,联合
自定义类型:结构体,枚举,联合 结构体 结构体类型的声明 1. 结构的基础知识 2.特殊的声明 3.结构体的自引用 4.结构体的定义和初始化 5.结构体内存对齐 6.修改默认对齐数 7.结构体传参 位 ...
- SV学习笔记—结构体及枚举类型及字符串
目录 1.结构体 1.1 压缩结构体 1.2 非压缩结构体 1.3联合结构体 2.枚举类型 3.字符串 1.结构体 Verilog的最大缺陷之一是没有数据结构,SV中可以使用struct语句创建结构, ...
- C语言自定义变量类型——结构体详解
文章目录 前言 为什么要学习结构体 什么是结构体 一.结构体:struct 1.结构体类型的声明 (1)结构体的基础知识 (2)结构体的声明 (3)特殊的声明 2.结构体的自引用 3.结构体变量的定义 ...
- 结构体,枚举类型与联合体
目录 编辑 一.结构体的基本使用 1.什么是结构体 2.结构体的一般声明 3.结构体的特殊声明 4.结构体的自引用 5.结构体变量的定义和初始化 二.结构体内存对齐 1.内存对齐规则 3.为什么会存 ...
最新文章
- Andriod绘图的基础知识
- Mac 新建unix可执行文件
- C#进行MapX二次开发之鹰眼实现
- @Transactional 使用
- iOS 直接使用16进制颜色
- Coursera自动驾驶课程第13讲:Least Squares
- 动画原理——用户交互:移动物体
- 使用Redis和Apache Kafka处理时间序列数据
- 安卓游戏时禁止状态栏下拉,如何在Android中禁用通知栏下拉菜单?
- linux内存管理_架构师必读:Linux 的内存分页管理
- jdk1.8中文帮助文档
- 软件定义和硬件重构知多少(三)
- 实现Promise的resolve/reject/then/all/race/finally/catch方法
- PostgreSQL checksum与Data Corruption
- 中国联通沃商店校园大使招募书
- ASP完美优化(不断更新)
- 成功的路上会布满荆棘
- 祖传Python代码
- vb 彩牛概率统计for Excel
- 2021.10.02超详细实现过程-Linux 环境下的简易聊天室,采用CS模型,实现多客户端之间的稳定数据传输。(添加好友,删除好友、屏蔽好友、查看好友列表(针对数据库的操作))