概述
本篇主要讲解一些自定义类型(结构体 ,枚举,联合体)
目录
1.结构体
1.1结构体基础
1.2结构体声明
1.3结构体的特殊声明
1.4结构体的自引用
1.5结构体变量的定义和初始化
1.6结构体内存对齐
’1.7修改默认对齐数
1.8结构体传参
2.位段
2.1位段是什么
2.2 位段的内存分配
2.3 位段的跨平台问题
3. 枚举
3.1 枚举类型的定义
3.2枚举的优点
3.3枚举的使用
4.联合体
4.1 联合体的定义
4.2 联合体的特点
4.3 联合体大小的计算
1.结构体
1.1结构体基础
在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类。结构体可以被声明为变量、指针或数组等,用以实现较复杂的数据结构。结构体同时也是一些元素的集合,这些元素称为结构体的成员(member),且这些成员可以为不同的类型,成员一般用名字访问。
1.2结构体声明
结构体的定义如下所示,struct为结构体关键字,tag为结构体的标志,member-list为结构体成员列表,其必须列出其所有成员;variable-list为此结构体声明的变量
struct tag
{
member-list; }variable-list;
下面举个例子
struct stu{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在学习小组
float score; //成绩
};
1.3结构体的特殊声明
这里的特殊声明是指在声明时可以不完全声明
//匿名结构体类型
struct
{
int a;
char b;
float c; }x;
struct
{
int a;
char b;
float c; }a[20], *p;
1.4结构体的自引用
//代码1
struct Node
{
int data;
struct Node* next;
};
//代码2
//typedef 为一个数据类型起一个新的别名,
typedef struct Node
{
int data;
struct Node* next; }Node;
1.5结构体变量的定义和初始化
定义及初始化介绍
struct Point
{
int x;
int y; }p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = {x, y};
举例
struct Stu //类型声明
{
char name[15];//名字
int age; //年龄
};
struct Stu s = {"lisi", 24};//初始化
也可以结构体嵌套初始化
struct Node
{
int data;
struct Point p;
struct Node* next;
}n1 = {10, {4,5}, NULL};
struct Node n2 = {20, {5, 6}, NULL};
1.6结构体内存对齐
我们计算结构体大小就要 学会 结构体内存对齐
结构体的大小不是结构体元素单纯相加就行的,因为我们主流的计算机使用的都是32bit字长的CPU,对这类型的CPU取4个字节的数要比取一个字节要高效,也更方便。所以在结构体中每个成员的首地址都是4的整数倍的话,取数据元素时就会相对更高效,这就是内存对齐的由来。每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。
我们首先就要知道结构体的对齐规则
1. 第一个成员在与结构体变量偏移量为 0 的地址处。2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数 与 该成员大小的 较小值 。VS 中默认的值为 83. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
下面练习1 练习2
练习4 ----结构体嵌套问题
’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("%dn", sizeof(struct S1));
printf("%dn", sizeof(struct S2));
1.8结构体传参
//结构体地址传参
void print2(struct S* ps) {
printf("%dn", ps->num);
}
int main()
{
print1(s); //传结构体
print2(&s); //传地址
return 0; }
结构体传参 可以直接传结构体也可以传地址,我们这里传的是地址
因为函数传参时,参数是需要压栈,会有时间和空间上的系统开销,假若传递一个结构体对象的时候,结构体过大,会使压栈的系统开销比较大,所以会导致性能的下降。
2.位段
2.1位段是什么
位段的声明和结构是类似的,有两个不同:1.位段的成员必须是 int、unsigned int 或signed int 。2.位段的成员名后边有一个冒号和一个数字。
struct A {
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
2.2 位段的内存分配
1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型2. 位段的空间上是按照需要以 4 个字节( int )或者 1 个字节( char )的方式来开辟的。3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
2.3 位段的跨平台问题
1. int 位段被当成有符号数还是无符号数是不确定的。2. 位段中最大位的数目不能确定。( 16 位机器最大 16 , 32 位机器最大 32 ,写成 27 ,在 16 位机器会出问题。3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。
3. 枚举
枚举(enum)类型是计算机编程语言中的一种数据类型。枚举类型:在实际问题中,有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等。如果把这些量说明为整型,字符型或其它类型显然是不妥当的。
3.1 枚举类型的定义
enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex//性别
{
MALE,
FEMALE,
SECRET
};
{} 中的内容是枚举类型的可能取值,也叫 枚举常量 。这些可能取值都是有值的,默认从 0 开始,一次递增 1 ,当然在定义的时候也可以赋初值。
3.2枚举的优点
1. 增加代码的可读性和可维护性2. 和 #define 定义的标识符比较枚举有类型检查,更加严谨。3. 防止了命名污染(封装)4. 便于调试5. 使用方便,一次可以定义多个常量
3.3枚举的使用
enum Color//颜色
{
RED=1,
GREEN=2,
BLUE=4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
clr = 5;
4.联合体
4.1 联合体的定义
//联合类型的声明
union Un
{
char c;
int i;
};
//联合变量的定义
union Un un;
//计算连个变量的大小
printf("%dn", sizeof(un));
4.2 联合体的特点
union Un
{
int i;
char c;
};
union Un un;
// 下面输出的结果是一样的吗?
printf("%dn", &(un.i));
printf("%dn", &(un.c));
//通过运行发现两个是相同的
4.3 联合体大小的计算
联合的大小至少是最大成员的大小。当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};
//大家可以试着输出一下看有什么发现
printf("%dn", sizeof(union Un1));
printf("%dn", sizeof(union Un2));
最后
以上就是畅快水杯为你收集整理的自定义类型详解————C语言1.结构体 2.位段3. 枚举 4.联合体的全部内容,希望文章能够帮你解决自定义类型详解————C语言1.结构体 2.位段3. 枚举 4.联合体所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复