【C语言进阶】自定义类型之结构体,枚举和联合

这篇具有很好参考价值的文章主要介绍了【C语言进阶】自定义类型之结构体,枚举和联合。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

人一能之,己百之;人十能之,己千之。                             ——《中庸》

【C语言进阶】自定义类型之结构体,枚举和联合 

目录

一.结构体

1.结构的基础知识

2.结构体的声明

3.结构体成员的类型

4.结构体变量的定义和初始化:

5.结构体成员的访问:

6.结构体传参 

7.结构体内存对齐:结构体的大小

8.为什么要有内存对齐?

二.结构体的位段

1.什么是位段:

2.位段的内存分配:

3.位段的跨平台问题

4.位段的应用:

三.枚举 

1.枚举的定义

2.枚举的优点:

四.联合(共用体)

1.联合体等定义:

2.联合体的大小


一.结构体

1.结构的基础知识

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

2.结构体的声明

结构体的定义如下所示,struct为结构体关键字,tag为结构体的标志,member-list为结构体成员列表,其必须列出其所有成员;variable-list为此结构体声明的变量。

struct tag {
 member-list
 } variable-list ; //这个;不能少

在结构体中,必须有struct tag和member-list是必须要有的,而variable-list是可以没有的,variable-list只是一个结构体变量,而且是全局变量,这里可以不写也行。

struct tag {
 member-list
 } ; 

3.结构体成员的类型

结构体成员可以是标量,数组,指针,甚至是其他结构体。当我们想定义一个人时,我们可能会想到他的身高,体重,名字等我们就用float来定义,体重用int,名字用char。

struct people
{
    int weight;//体重
    char name[20];//数组来存名字
    float height;//身高
};

4.结构体变量的定义和初始化:

struct people
{
    int weight;//体重
    char name[20];//名字
    float height;//身高
};
int main()
{
    struct people man = { 55,"小陈",172 };//man就是结构体变量,是局部变量
    struct people max = { .weight = 55,.name = "小陈",.height = 172 };
    //这两种结构体的初始化都可以
    return 0;
}

typedef是在计算机编程语言中用来为复杂的声明定义简单的别名,它与宏定义有些差异。它本身是一种存储类的关键字,与auto、extern、mutable、static、register等关键字不能出现在同一个表达式中。

这里我们写struct people感觉有点麻烦,我们就可以使用typedef来给结构体定义一个简单的别名,之后我们就可以使用别名来代替结构体类型。上述初始化代码我们就可以这样写。

typedef struct people M;
struct people//第一次使用时不能用M来代替
{
    int weight;//体重
    char name[20];//名字
    float height;//身高
};
int main()
{
    M man = { 55,"小陈",172 };
    //这里就是用M来代替struct people
    M max = { .weight = 55,.name = "小陈",.height = 172 };
    //这两种结构体的初始化都可以
    return 0;
}

当结构体的成员有结构体,我们又该如何对结构体初始化呢?

struct book
{
    char name[20];
    struct people;
    int price;
};
struct people
{
    int weight;
    char name[10];
    float height;
};
int main()
{
    struct book b1 = { "活着",{60,"富贵",170},50 };//用大括号括起来
    //从结构体book里面从上往下初始化结构体成员
    return 0;
}

5.结构体成员的访问:

1.结构体变量.结构体成员名

2.结构体指针->结构体成员名

struct people
{
    int weight;
    char name[10];
    float height;
};
void print(struct people* b2)
{
    printf("%d %s %f\n", b2->weight, b2->name, b2->height);
}
int main()
{
    struct people b1 = { 55,"小陈",172};
    printf("%d %s %f\n", b1.weight, b1.name, b1.height);
    print(&b1);
    return 0;
}

【C语言进阶】自定义类型之结构体,枚举和联合

6.结构体传参 

结构体传参也有两种,一种是传结构体变量过去,还有一种就是传地址过去,这两者有什么区别吗?

struct people
{
    int weight;
    char name[10];
    float height;
};
void print1(struct people* b2)
{
    printf("%d %s %.1f\n", b2->weight, b2->name, b2->height);
}
void print2(struct people b2)//形参
{
    printf("%d %s %.1f\n", b2.weight, b2.name, b2.height);
}
int main()
{
    struct people b1 = { 55,"小陈",172};
    printf("%d %s %.1f\n", b1.weight, b1.name, b1.height);
    print1(&b1);//传地址
    print2(b1);//传变量,实参
    return 0;
}


当我们传参的时候,如果传的结构体变量,那形参就要开辟结构体成员内存的总空间来接收实参,因为函数传参的时候,参数是需要压栈的。如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降。

所以我们尽量使用传地址的形式,也就是传指针,因为我们知道指针大小就是4或者8个字节。

所以这样就比较节省空间。

结论:结构体传参的时候,要传结构体的地址。

7.结构体内存对齐:结构体的大小

C语言马上都已经学完了,我们还没学过计算结构体的大小。今天我们就将好好的学习一下,在这里我会详细的讲解如何计算结构体的大小。

struct A
{
	int a;
	char c1;
}s1;
struct B
{
	char c1;
	int a;
	char c2;
}s2;
struct C
{
	char c1;
	int a;
	char c2;
	char c3;
}s3;
int main()
{
	printf("%d\n", sizeof(struct A));
	printf("%d\n", sizeof(struct B));
	printf("%d\n", sizeof(struct C));
	return 0;
}

在这里计算结构体的大小会不会是A结构体有一个int和char,大小是5个字节。B有6个字节,C有7个字节。其实想想也不会这么简单,不然我们也不会系统的学习。

【C语言进阶】自定义类型之结构体,枚举和联合

很奇怪,为什么结构体的大小会是8,12,12呢?而且结构体C还比结构体B的变量多一个。

这里就要请出结构体内存对齐这个东西了。

1.结构体的第一个成员永远放在0偏移处。

2.第二个成员开始,以后每一个成员都要到某个对齐数的整数倍处,这个对齐数是:成员自身大小和默认对齐数的较小值。

注:VS环境下,默认对齐数是8。gcc环境下,没有默认对齐数,对齐数就是成员自身的大小。

3.当成员全部存放进去后,结构体的总大小是所有成员的对齐数中最大对齐数的整数倍。如果不够,则浪费空间对齐。

4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

上述的话是什么意思呢?我们使用上面的结构体例子来说明一下,就懂了。

 对于结构体A:

【C语言进阶】自定义类型之结构体,枚举和联合

对于结构体B:

【C语言进阶】自定义类型之结构体,枚举和联合 

对于结构体C:

【C语言进阶】自定义类型之结构体,枚举和联合

 对于结构体嵌套结构体的:

就是上面的第四点:如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

struct A
{
	char c1;
	int a;
	double b;
};
struct B
{
	char c2;
	int a1;
	struct A s1;
};
int main()
{
	printf("%d", sizeof(struct B));
	return 0;
}

【C语言进阶】自定义类型之结构体,枚举和联合

8.为什么要有内存对齐?

1. 平台原因:

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

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

【C语言进阶】自定义类型之结构体,枚举和联合
总体来说:
结构体的内存对齐是拿空间来换取时间的做法。

struct A//这个结构体的大小是8
{
	char c1;
	char c2;
	int a;
};
struct B//这个结构体的大小是12
{
	char c1;
	int a;
	char c2;
};

虽然结构体成员都是一样,但是顺序不同也会使结构体的大小不同。 

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

二.结构体的位段

1.什么是位段:

顾名思义位段就是二进制位(比特位)。

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

1.位段的成员必须是整型家族的:int,unsigned int或者signed int,char。

2.位段成员名后边有一个冒号和一个数字。

2.位段的内存分配:

1.位段的空间是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。

2.位段涉及很多不确定的因素,位段是不跨平台的,注意可移植性的程序应当避免使用位段。

struct A
{
	char a : 3;//这些就是位段
	char b : 4;
	char c : 5;
	char d : 4;
}S;
int main()
{
	S.a = 10;
	S.b = 12;
	S.c = 3;
	S.d = 4;
	return 0;
}

1.我们假设分配到内存空间的比特位是从右向左的

2.分配的内存剩余的比特位不够使用时,浪费掉。

VS2022环境测试数据:

【C语言进阶】自定义类型之结构体,枚举和联合

结果确实按照我们假设的一样。

3.位段的跨平台问题

1. int位段被当成有符号数还是无符号数是不确定的。
2.位段中最大位的数目不能确定。(16位机器最大16, 32位机器最大32, 写成27, 在16位机器会出问题。
3.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4.当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。
总结:
跟结构相比, 位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。

4.位段的应用:

【C语言进阶】自定义类型之结构体,枚举和联合

在网络上传输数据的时候,可以通过位段来节省空间。

三.枚举 

1.枚举的定义

枚举顾名思义就是一一给列举出来。

想我们现实中星期,性别和月份等可以一一列举出来。

枚举的可能取值默认时从0开始的,依次递增1。

enum sex
{
    MALE,
    FEMALE,
    SECRET
};
int main()
{
    enum sex s = MALE;
    printf("%d\n", MALE);
    printf("%d\n", FEMALE);
    printf("%d\n", SECRET);
    return 0;
}

【C语言进阶】自定义类型之结构体,枚举和联合

enum sex
{
    MALE,
    FEMALE=5,//也可赋值,后面依次自增1
    SECRET
};
int main()
{
    enum sex s = MALE;
    printf("%d\n", MALE);
    printf("%d\n", FEMALE);
    printf("%d\n", SECRET);
    return 0;
}

【C语言进阶】自定义类型之结构体,枚举和联合 

2.枚举的优点:

为什么使用枚举?
我们可以使用#define定义常量,为什么非要使用枚举?枚举的优点:
1.增加代码的可读性和可维护性。
2.和#define定义的标识符比较枚举有类型检查,更加严谨。

3.便于调试。
4.使用方便, 一次可以定义多个常量。

四.联合(共用体)

1.联合体等定义:

联合也是一种特殊的自定义类型。

这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合叫共用体)

union un 
{
	char c;
	int i;
};
int main()
{
	union un u;
	printf("%d\n", sizeof(u));
    return 0;
}

【C语言进阶】自定义类型之结构体,枚举和联合

特点:联合的成员的共用同一块空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

2.联合体的大小

联合体的大小至少是最大成员的大小

当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

这里的对齐规则是和结构体的内存对齐是一样的,但是联合体是公用一块空间的。

比如我们举例说明:

union un 
{
	char c;
	int i;
};
int main()
{
	union un u;
	printf("%d\n", sizeof(u));
	printf("%p\n", &u);
	printf("%p\n", &(u.i));
	printf("%p\n", &(u.c));
	return 0;
}

【C语言进阶】自定义类型之结构体,枚举和联合

 【C语言进阶】自定义类型之结构体,枚举和联合

之前我们不是写了一个判断大小端的题吗?我们通过int a=1;(char*)p=&a, 强制类型转换,访问一个字节来判断。但是这里我们可以通过共用体来实现。非常的简单。

union un 
{
	char c;
	int a;
};
int main()
{
	union un s;
	s.a = 1;
	if (s.c == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

【C语言进阶】自定义类型之结构体,枚举和联合

全部的内容就结束了,感谢支持。 

 文章来源地址https://www.toymoban.com/news/detail-421984.html

到了这里,关于【C语言进阶】自定义类型之结构体,枚举和联合的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【再识C进阶4】详细介绍自定义类型——结构体、枚举和联合

           在上一篇博客中,我们已经详细地学习了字符分类函数、字符转换函数和内存函数。那这一篇博客和上一篇博客的关系不是那么相连。        这一篇博客主要介绍一下 自定义类型 ,因为在解决实际问题时, 由于世界上的因素有很多,我们需要建立不同的数据

    2024年02月08日
    浏览(48)
  • 【C语言】自定义类型:结构体、枚举、联合

    目录 前言: 一、结构体 (1)结构体的特殊声明 (2)结构体的自引用 (3)结构体嵌套初始化 (4)结构体内存对齐 (5)修改默认对齐数 (6)结构体传参 (7)位段 二、枚举 (1)枚举的定义 (2)枚举的优点 (3)枚举的使用 三、联合(共用体) (1)联合类型的定义 (

    2024年02月16日
    浏览(44)
  • C语言—自定义类型(结构体、枚举、联合)

    结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。 实例一(描述一本书): 在声明结构的时候,可以不完全的声明。 实例一: 注:匿名结构体类型创建好之后只能用一次(没有标签构不成结构体类型) 实例一: 注:在结构中包含一个类型

    2024年02月06日
    浏览(45)
  • 【C语言】——自定义类型详解:结构体,枚举,联合

    大家好,今天为大家分享一下C语言中的那些自定义类型:结构体,枚举,联合,还有之前可能不曾了解的结构体内存对齐、位段等知识点!!! 一、结构体 结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。 结构的声明 : 例如描述一个学生

    2024年02月07日
    浏览(50)
  • 详解C语言自定义类型(结构体,枚举,联合)

    ❤️ 作者简介 :RO-BERRY 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识,对纯音乐有独特的喜爱 📗 日后方向 : 偏向于CPP开发以及大数据方向,如果你也感兴趣的话欢迎关注博主,期待更新 🎄结构体是一些值的集合,这些值称为成员变量。结构的每个成员可以是不

    2024年02月16日
    浏览(39)
  • C语言自定义类型 — 结构体、位段、枚举、联合

    本期主要对通讯录三篇博客文章进行补充 通讯录文章:通讯录系列文章 对 结构体 进行详细介绍,其次讲解位段、枚举、联合体 在C语言中,结构是一种用户自定义的数据类型,它可以由不同类型的数据成员组成,每个数据成员可以是不同的数据类型。 结构的作用是将多个不

    2024年02月14日
    浏览(42)
  • 手撕自定义类型:结构体,枚举,联合——【C语言】

      在开始学习之前我们先来欣赏一下五岳之一华山的风景,来营造一个好心情,只有一个好心情我们才能更好的学习 目录 结构体 1 结构体的声明 1.1 结构的基础知识 1.2 结构的声明 1.3 特殊的声明 1.4 结构的自引用 1.5 结构体变量的定义和初始化  1.6 结构体内存对齐(重点)

    2024年02月16日
    浏览(43)
  • C语言——自定义类型详解[结构体][枚举][联合体]

    我打算把结构体、枚举、联合体的重点内容总结一下,方便后期复习的时候能够更快,更准确的去拾取遗忘的知识。也希望能给大家起到借鉴的作用,不足的地方,请多多包涵。(不足的地方,也希望大家能够指出来) 结构体是一些值的集合,这些集合称为成员变量,结构体

    2024年02月13日
    浏览(41)
  • 【C语言】自定义类型:结构体【结构体内存具详细】,枚举,联合

      目录 一、结构体 1.结构的声明  2.特殊的声明 3.结构的自引用 4.结构体变量的定义和初始化   5.结构体内存对齐(重点来了) 6.为什么会存在内存对齐  7.修改默认对齐数 8.结构体传参 二、位段 1.什么是位段 2.位段的内存分配 3.位段的跨平台问题 三、枚举 1.枚举类型的定

    2024年02月07日
    浏览(49)
  • 一篇博客学会系列(2)—— C语言中的自定义类型 :结构体、位段、枚举、联合体

    目录  前言 1、结构体 1.1、结构体类型的声明 1.2、特殊的结构体类型声明 1.3、结构体的自引用 1.4、结构体的定义和初始化 1.5、结构体成员变量的调用 1.6、结构体内存对齐  1.6.1、offsetof 1.6.2、结构体大小的计算 1.6.3、为什么存在内存对齐?  1.7、 修改默认对齐数 1.8、结构

    2024年02月08日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包