iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言自定义类型详解(结构体、枚举、联合体和位段)
  • 618
分享到

C语言自定义类型详解(结构体、枚举、联合体和位段)

2024-04-02 19:04:59 618人浏览 独家记忆
摘要

目录前言一、结构体1、结构体类型的声明2、结构体的自引用3、结构体变量的定义和初始化4、结构体内存对齐5、结构体传参二、位段1、位段的定义 2、位段的内存分配3、位段的应用

前言

在这里插入图片描述

一、结构体

1、结构体类型的声明

当我们想要描述一个复杂变量——学生,可以这样声明。

✒️代码展示:


struct Stu
{
    char name[20];//名字
    int age;//年龄
    char sex[5];//性别
    char id[20];//学号
}s1;//分号不能丢
int main()
{
    struct Stu s2; 
    return 0;
}

🔖解释说明:

  • struct是结构体的关键字
  • Stu是结构体标签名
  • struct Stu是结构体的类型
  • 大括号内包围的是结构体成员变量的列表
  • 变量s1是类型为struct Stu的全局变量,变量s2是该类型的局部变量

在声明结构时,也有特殊的声明,比如不完全声明——匿名结构体类型,省略掉了结构体标签。

✒️代码展示:


struct
{
    int a;
    char b;
    float c;
}x;
struct
{
    int a;
    char b;
    float c;
}a[20], *p;

那么,此时,问题来了!

在上面的代码基础上,p = &x,这样的代码合理吗?

在这里插入图片描述

而且,像这样的匿名结构体类型只能使用一次,因为没有标签名。

2、结构体的自引用

众所周知,函数可以自己调用自己,叫做函数的递归,那么结构体是否也有自己引用自己呢?如果有又是如何实现的呢?

✒️代码展示:


//代码一:
struct N
{
    int data;
    struct N next;
};
//代码二:
struct node
{
    int data;
    struct Node* next;
};
//代码三:
typedef struct
{
    int data;
    Node* next;
}Node;
//代码四:
typedef struct Node
{
    int data;
    struct Node* next;
}Node;

🔖解释说明:

代码一:

这样自引用是不正确的。当想要计算struct N类型所占空间大小时,就会出现疯狂套娃现象,无法计算结果,因此是不可取的

代码二:

这才是自引用的正确打开方式。data中存放的数据,next中存放着下一个struct Node类型数据的地址

代码三:

该代码想要实现匿名结构体的自引用,但这样做是不可取的。因为需要完整的定义了该结构体才可以重新命名为Node。然而定义的成员列表中又有Node*,先后问题产生了。

代码四:

可以通过这种重定义方式实现自引用。

3、结构体变量的定义和初始化

既然已经有了结构体类型,那么对其定义和初始化就变得非常的简单

✒️代码展示:


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 = {"zhangsan", 20};//初始化
struct Node
{
    int data;
    struct Point p;
    struct Node* next;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化

4、结构体内存对齐

掌握了结构体的基本使用,还应当重点了解结构体内存对齐问题从而计算结构体的大小,这是一个关于结构体的重点考点

在这里插入图片描述

结构体的对齐规则:

  1. 第一个成员在与结构体变量偏移量为0的地址处。
  2. 其他成员变量需要对齐到对齐数的整数倍的地址处。
    对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。
    VS中默认的值为8,linux没有默认对齐数
  3. 结构体总大小为最大对齐数的整数倍。
  4. 当嵌套结构体时,嵌套的结构体对齐需要到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数的整数倍(包含嵌套结构体的对齐数)。

✒️代码展示:


//练习1
struct S1
{
    char c1;
    int i;
    char c2;
};
printf("%d\n", sizeof(struct S1));
//练习2
struct S2
{
    char c1;
    char c2;
    int i;
};
printf("%d\n", sizeof(struct S2));
//练习3
struct S3
{
    double d;
    char c;
    int i;
};
printf("%d\n", sizeof(struct S3));
//练习4-结构体嵌套问题
struct S4
{
    char c1;
    struct S3 s3;
    double d;
};
printf("%d\n", sizeof(struct S4));

👁效果展示:

在这里插入图片描述

🔖解释说明:

结构体类型struct S1和struct S2两者的成员组成是一样的,但是定义顺序有所差别,后者与前者相比将占用空间小的变量集中在了一起,导致两者在遵循结构体对齐条件下,所占内存大小不一样。做个对比吧!

在这里插入图片描述

结构体类型struct S3和struct S4是另外两个典型例子,后者嵌套前者。

在这里插入图片描述

简而言之,该做法就是为了拿空间换取时间

如果。。。

在这里插入图片描述

另外。。。

结构在对齐方式不合适的时候,我么可以自己更改默认对齐数。

这里我们将使用预处理指令#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; 
}

👁效果展示:

在这里插入图片描述

🔖解释说明:

在这里插入图片描述

5、结构体传参

✒️代码展示:


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->data[2]);
}
int main()
{
    print1(s);  //传结构体
    print2(&s); //传地址
    return 0;
}

👁效果展示:

在这里插入图片描述

🔖解释说明:

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,导致性能的下降。比如在这里,如果直接传值s的话,由于结构体中创建了一个很大的数组data,导致结构体过大,传参时浪费的内存空间很大,效率低下。但是如果传址&s的话,作为一个指针,占四个字节,极大提高了运行效率。

简而言之,结构体传参时,传结构体的地址更好

二、位段

1、位段的定义 

位段C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域” 。利用位段能够用较少的位数存储数据。

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

  • 位段的成员必须是 int、unsigned int 、signed int、char 。
  • 位段的成员名后边有一个冒号和一个数字(指该成员占的比特位)。

✒️代码展示:


struct A
{
    int _a:2;
    int _b:5;
    int _c:10;
    int _d:30;
};

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;
}
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

🔖解释说明:

在VS编译器中开辟了空间以后,先使用低地址再使用高地址。并且剩余的比特位不够下一个变量存储时,那这一片空间将会被浪费。

在这里插入图片描述

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

3、位段的应用

在这里插入图片描述

🔖解释说明:

上图是网络上IP数据包的格式,当你想要在网络上发一条消息给你的好友,信息是需要进行分装的,消息作为数据只是传输的一部分,还有一部分传输的是分装中的其他信息。比如4位版本号,4位首部长度,这些信息只需要4个bit,如若不使用位段,直接每个部分一个整形的给空间,就会造成空间的大量浪费。

三、枚举

1、枚举类型的定义

数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠。枚举在日常生活中很常见,例如表示星期的SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY就是一个枚举。

2、枚举的优点

枚举的优点

  1. 代码的可读性变高和可维护性变强
  2. 和#define定义的标识符相比较枚举更加严谨,因为有类型检查。
  3. 防止命名污染的现象
  4. 方便调试,且使用方便,可以一下子定义很多常量

3、枚举的使用

枚举的说明与结构和联合相似, 其形式为:


enum 枚举名
{
    标识符[=整型常数],
    标识符[=整型常数],
    ...
    标识符[=整型常数]
} 枚举变量;

如果枚举没有初始化,即省掉"=整型常数"时, 则从第一个标识符开始,顺次赋给标识符0, 1, 2, …但当枚举中的某个成员赋值后,其后的成员按依次加1的规则确定其值。

✒️代码展示:


//代码1
enum Num1
{
    x1,
    x2,
    x3,
    x4
}x;
//代码2
enum Num2
{
    y1,
    y2 = 0,
    y3 = 50,
    y4
};
int main()
{
    printf("%d %d %d %d\n", x1, x2, x3, x4);
    printf("%d %d %d %d\n", y1, y2, y3, y4);
    return 0;
}

👁效果展示:

在这里插入图片描述

注意

  1. 枚举中每个成员(标识符)结束符是==","== 不是";", 最后一个成员可省略","。
  2. 初始化时可以赋负数, 以后的标识符仍依次加1。
  3. 枚举变量只能取枚举说明结构中的某个标识符常量。
  4. 枚举值是常量,不是变量,不能在程序中用赋值语句再对它赋值(比如上面的代码出现y3 = 3; ❎)。
  5. 只能把枚举值赋予枚举变量,不能把元素的数值直接赋予枚举变量,除非进行了强制类型转换(比如上面的代码出现x = x2✔️ x = 1❎x = (enum Num1)1✔️)

四、联合体(共用体)

1、联合体的定义

需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”类型结构,简称共用体,也叫联合体。

2、联合体的特点

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

✒️代码展示:


//联合类型的声明
uNIOn Un
{
    char c;
    int i;
};
//联合变量的定义
union Un un;
int main()
{
    //例①
    printf("%p\n", &(un.i));
    printf("%p\n", &(un.c));
    //例②
    un.i = 0x11223344;
    un.c = 0x55;
    printf("%x\n", un.i);
    return 0;
}

👁效果展示:

在这里插入图片描述

🔖解释说明:

通过例①的结果,我们可以直观发现成员变量c和成员变量i共用地址

例②更加证实这一点,由于大小端存储,变量i是以44 33 22 11这样的顺序存储的,因为变量c与其公用地址,因此55将44覆盖,在内存中变量i为55 33 22 11,打印出来为11 22 33 55

联合体的相关应用

在之前我们已经学会了判断计算机大小端的方法,这里可以通过共用体的特点来实现

#include <stdio.h>union Un{    char c;    int i;}num;int main(){    num.i = 1;    if(num.c == 1)    {        printf("小端存储")    }    else    {        printf("大端存储")    }    return 0;}

向成员变量i中存放一个1,查看成员变量c的值,由于该变量是char类型,因此只访问了第一个字节。

3、联合体的大小计算

联合体大小计算规则

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

✒️代码展示:


#include <stdio.h>
union Un
{
    char c;
    int i;
}num;
int main()
{
    num.i = 1;
    if(num.c == 1)
    {
        printf("小端存储")
    }
    else
    {
        printf("大端存储")
    }
    return 0;
}

👁效果展示:

在这里插入图片描述

总结

到此这篇关于C语言自定义类型的文章就介绍到这了,更多相关C语言自定义类型内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C语言自定义类型详解(结构体、枚举、联合体和位段)

本文链接: https://www.lsjlt.com/news/133232.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言自定义类型详解(结构体、枚举、联合体和位段)
    目录前言一、结构体1、结构体类型的声明2、结构体的自引用3、结构体变量的定义和初始化4、结构体内存对齐5、结构体传参二、位段1、位段的定义 2、位段的内存分配3、位段的应用...
    99+
    2024-04-02
  • C语言自定义数据类型的结构体、枚举和联合详解
    结构体基础知识 首先结构体的出现是因为我们使用C语言的基本类型无法满足我们的需求,比如我们要描述一本书,就需要书名,作者,价格,出版社等等一系列的属性,无疑C语言的基本数据类型无法解...
    99+
    2024-04-02
  • C语言中的自定义类型之结构体与枚举和联合详解
    目录1.结构体1.1结构的基础知识1.2结构的声明1.3特殊的声明1.4结构的自引用1.5结构体变量的定义和初始化1.6结构体内存对齐1.7修改默认对齐数1.8结构体传参2.位段2....
    99+
    2024-04-02
  • C语言自定义类型超详细梳理之结构体枚举联合体
    目录一、什么是结构体1.结构体实现2.匿名结构体类型3.结构体自引用4.结构体的内存对齐5.结构体位段 二、什么是枚举1.枚举类型的定义2.枚举的优点三、联合(共用体)1.什么是联合...
    99+
    2024-04-02
  • C语言结构体,枚举,联合体详解
    目录1.什么是结构体、枚举、联合体2.定义结构体2.1 包含结构体成员变量、variable2.2 tag、结构体成员变量2.3 用结构体声名变量2.4 用typedef 创建新类型...
    99+
    2024-04-02
  • c语言中如何自定义结构体、位段和枚举
    这篇文章主要介绍了c语言中如何自定义结构体、位段和枚举的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇c语言中如何自定义结构体、位段和枚举文章都会有所收获,下面我们一起来看看吧。结构体类型创建:struct St...
    99+
    2023-06-17
  • C语言关于自定义数据类型之枚举和联合体详解
    目录前言枚举枚举类型的定义枚举类型的优点枚举类型的使用枚举中需要注意的点联合体联合体类型的定义联合体的特点联合体的使用联合体存在内存对齐结语前言 在C语言的自定义数据类型中,除了我们...
    99+
    2024-04-02
  • C语言深入探究自定义类型之结构体与枚举及联合
    目录1.结构体1.1结构体类型的声明1.2结构的自引用1.3结构体变量的定义和初始化1.4结构体内存对齐1.5结构体传参1.6结构体实现位段(位段的填充&可移植性)2.枚举2...
    99+
    2024-04-02
  • 详解C语言结构体,枚举,联合体的使用
    目录一、匿名结构体二、结构体的自引用1、声明时不要自己引用自己2、结构体重命名时不能使用重命名三、结构体内存对齐规则1、结构体内存计算2、结构体嵌套3、通过调整结构体成员顺序,压缩内...
    99+
    2024-04-02
  • C语言结构体,枚举,联合体如何使用
    本篇内容介绍了“C语言结构体,枚举,联合体如何使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、匿名结构体struct{ &n...
    99+
    2023-07-02
  • 怎么在C语言中自定义结构体和枚举
    这篇文章将为大家详细讲解有关怎么在C语言中自定义结构体和枚举,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。C语言是什么C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发,使...
    99+
    2023-06-14
  • C语言枚举与联合体深入详解
    目录前言枚举枚举的定义枚举的使用枚举的优点联合(共用体)联合体的定义联合体的特点联合体大小的计算总结前言 在C语言中,有三个自定义类型——结构体,枚举,联合,...
    99+
    2024-04-02
  • c语言如何自定义结构体类型
    在C语言中,可以使用`typedef`关键字来自定义结构体类型。`typedef`关键字用于为已存在的类型定义一个新的名称。以下是定...
    99+
    2023-09-04
    c语言
  • C语言中枚举和联合体的示例分析
    这篇文章主要介绍了C语言中枚举和联合体的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。枚举什么是枚举?顾名思义,就是一一列举,把所有的情况,所有的取值,一一列举出来。...
    99+
    2023-06-25
  • 详解C语言结构体的定义和使用
    目录1.1:结构体用来干嘛?1.2:结构体变量的基本定义格式1.3:结构体变量的定义1.4结构体变量的三种引用方法2.结构体变量的使用(直接使用结构体变量)2.1输出结果3....
    99+
    2024-04-02
  • C语言中联合体与共用体和枚举使用语法示例
    目录联合体/共用体-union枚举-enum联合体/共用体-union 声明联合体的语法格式typedef union 联合体名 {数据类型 成员名1;...
    99+
    2022-12-26
    C语言联合体 C语言共用体 C语言枚举
  • C语言超详细讲解结构体与联合体的使用
    目录结构体offsetof-宏位段枚举联合体(共用体)结构体 结构体内存对齐问题: 当我们在计算结构体的大小时,我们便需要清楚的知道结构体内存对齐是什么。 存在内存对齐的原因可细分为...
    99+
    2024-04-02
  • C语言结构体数组的定义和使用详解
    目录介绍结构体数组定义时初始化补充介绍 一个结构体变量可以存放一个学生的一组信息,可是如果有 10 个学生呢?难道要定义 10 个结构体变量吗?难道上面的程序要复制和粘贴 10 次吗...
    99+
    2024-04-02
  • c语言结构体和联合体的区别是什么
    结构体和联合体在C语言中都是用来存储多个不同类型的数据的数据结构,但它们之间有一些重要的区别: 结构体(struct):结构体中的...
    99+
    2024-03-15
    c语言
  • C语言之结构体定义typedef struct用法详解
    在C语言中,使用struct关键字可以定义一个结构体类型,用于存储不同类型的数据。为了方便使用,可以使用typedef关键字给结构体...
    99+
    2023-08-09
    C语言
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作