C语言——自定义类型详解[结构体][枚举][联合体]

news2024/12/23 0:31:10

自定义类型详解

  • 前言:
  • 一、结构体
    • 1.1结构体的声明
    • 1.2结构体内存对齐
    • 1.3位段(位域)
  • 二、枚举
    • 2.1枚举类型的定义
    • 2.2枚举类型的优点
    • 2.3枚举的使用
  • 三、联合体
    • 3.1联合体类型的定义
    • 3.2联合体的特点
    • 3.3联合体大小的计算

前言:

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

一、结构体

1.1结构体的声明

结构体是一些值的集合,这些集合称为成员变量,结构体的每个成员可以是不同类型的变量。
结构体的声明:
在这里插入图片描述
结构体特殊声明:匿名结构体
如:

struct
{
int a;
char b;
float c;
}x;

结构体的自引用:

typedef struct
{
int data;
struct node* next;
}Node;
这样写代码不行,匿名结构体不要自引用
比较好的自引用方式:
typedef struct node
{
int data;
struct node* next;
}Node;
先用结构体类型,Node命名在后面

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

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={“pan long”,22};//初始化
结构体嵌套初始化:
struct Node
{
int data;
struct point;
struct Node* next;
}n1={22,{4,5},NULL};
struct Node n2={22,{6,7},NULL};//结构体嵌套初始化

1.2结构体内存对齐

结构体大小:

#include <stdio.h>
struct s1
{
    char c1;//1
    int i;//4
    char c2;//1
};
struct s2
{
    double d;//8
    char c;//1
    int i;//4
};
//结构体嵌套问题
struct s3
{
    char a;//1
    struct s2 S2;//16
    double d;//8
};
int main()
{
    printf("%d\n", sizeof(struct s1));//打印12
    printf("%d\n", sizeof(struct s2));//打印16
    printf("%d\n", sizeof(struct s3));//打印32
    return 0;
}

上面的现象分析:我们发现结构体成员不是按照顺序在内存中连续存放的,有一定的对齐规则
结构体内存对齐的规则:
1.结构体的第一个成员永远放在相较于结构体变量起始位置的偏移量为0的位置。
2.从第二个成员开始,往后的每个成员都要对齐到某个对齐数的整数倍处。
对齐数:结构体成员自身的大小和默认对齐数的较小值。
VS上默认对齐数是8
gcc 没有默认对齐数,对齐数是结构体成员的自身大小
3.结构体的总大小,必须是最大对齐数的整数倍。
最大对齐数是:所以成员的对齐数中最大的值。
为什么存在内存对齐?

1.平台原因:不是所以的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定的类型的数据,否则就会硬件异常。
2.性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因是:为了访问未对齐的内容,处理器需要做两次内存访问;而对齐的内存访问仅需一次访问。
总结:结构体的内存对齐是拿空间来换取时间的做法。

怎么修改默认对齐数?

#pragma是预处理命令,我们使用它可以改变默认对齐数。
如:#pragma pack(8)//设置默认对齐数为8
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
结论:结构体在对齐方式不合适的时候,我们可以自己改默认对齐数。

结构体传参:
有两种方式:

//定义一个结构体
struct S
{
    int data[100];
    int num;
};
struct S s = { {1,2,3,4},1000 };
void printf1(struct S s)
{
    printf("%d\n", s.num);
}
void printf2(  struct S* ps)
{
    printf("%d\n", ps->num);
}
int main()
{
    printf1(s);//值传参
    printf2(&s);//地址传参
    return 0;
}

地址传参更好
原因:
函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。如果传一个结构体对象,结构体够大,参数压栈的时候开销比较大,所以会导致性能的下降。
结论:结构体传参的时候,要传结构体的地址。

1.3位段(位域)

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

  1. 位段的成员必须是int 、unsigned int、或者 signed int。
  2. 位段的成员名后边有一个冒号和一个数字
    如:
    A就是一个位段类型
#include <stdio.h>
struct A
{
//占的是二进制位
    int _a : 2;
    int _b : 5;
    int _c : 10;
    int _d : 30;
};
int main()
{
    printf("%d\n",sizeof(struct A));//打印结果为8
}

位段的内存分配:
位段的成员可以是int 、unsigned int、signed int或者是char(属于整型家族)的类型。
位段在空间上是按照需要以4个字节和1个字节方式一次性去开辟得。
位段涉及很多不确定得因素,位段是不跨平台的,
例子:

#include <stdio.h>
struct S
{
    char a : 3;
    char b : 4;
    char c : 5;
    char d : 4;
};
int main()
{
    struct S s = { 0 };
    s.a = 10;
    s.b = 12;
    s.c = 3;
    s.d = 4;
    return 0;
}

空间是如何开辟得?
在这里插入图片描述
位段跨平台问题:

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

二、枚举

2.1枚举类型的定义

枚举就是列举的意思,把可能的取值一一列举。
如:一个星期有7天,它是有限得,那么我们就可以一一列举。
一年有12个月,它是有限得,那么我们可以一一列举。

enum Day //星期
{
Mon,Tues,Wed,Thur,Fri,Sat,Sun
};
enum Sex //性别
{
Male,Female,Secret
};
以上都是枚举类型
{}中的内容是枚举类型的可能取值,也叫做枚举常量.
这些可能取值都是有值的,默认从0开始,依次递增1,在声明枚举类型的时候也可以赋初值。

2.2枚举类型的优点

枚举类型的优点:

  1. 增加代码的可读性和可维护性。
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
  3. 便于调试。
  4. 使用方便,一次可以定义多个常量。

2.3枚举的使用

#include <stdio.h>
enum color
{
    red = 1,
    green = 2,
    blue = 4
};
int main()
{
    enum color  s= red;
   // s = 3;//在c++里无法从int型转换为枚举类型
    printf("%d\n", s);
    return 0;
}

三、联合体

3.1联合体类型的定义

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

#include <stdio.h>
//联合体类型声明
union un
{
    char c;
    int i;
};
int main()
{
    union un s;//联合体变量的定义
    printf("%d\n", sizeof( s));//计算共用体变量的大小,打印结果为5
    return 0;
}

3.2联合体的特点

联合体的成员是共用同一块内存空间,联合体变量的大小,至少是最大成员的大小(联合体至少能保存最大的那个成员)
例子:

#include <stdio.h>
union S
{
    char a;
    int i;
}s = {0};
int main()
{
    s.i = 1;
    printf("%d\n", s.a);//打印1,说明是小端
    s.i = 0x11223344;//小端存储,低字节内容存到低地址中
    s.a = 0x55;
    printf("%x\n", s.i);//打印0x11223355
    return 0;
}

3.3联合体大小的计算

联合的大小至少是最大成员的大小
当最大成员大小不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍。
#include <stdio.h>
union S
{
char a[5];//5
int i;//4
} s;
int main()
{
//共用体占多少内存空间
printf(“%d\n”, sizeof(s));//打印结果为8
return 0;
}

1、最大成员是5个字节。
2、最大成员不是最大对齐数的整数倍4(char为1,int为4),让他变成整数倍,所以打印结果为8.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/880848.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

457. 环形数组是否存在循环

457. 环形数组是否存在循环 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a;经验吸取 原题链接&#xff1a; 457. 环形数组是否存在循环 https://leetcode.cn/problems/circular-array-loop/description/ 完成情况&#xff1a; 解题思路…

01|Java中常见错误或不清楚

补充&#xff1a;length vs length() vs size() 1 java中的length属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了length这个属性. 2 java中的length()方法是针对字符串String说的,如果想看这个字符串的长度则用到length()这个方法. 3.java中的siz…

你是否知道,汽车充电桩控制主板也有可调性?

你是否知道&#xff0c;汽车充电桩控制主板也有可调性?它可以随着使用环境的改变&#xff0c;调整充电桩的参数&#xff0c;满足不同的需求。那么&#xff0c;它的可调性到底体现在哪些方面呢? 汽车充电桩控制板的可调性主要体现在以下三个方面&#xff1a; 1. 设备的参数调节…

nodejs+vue+elementui考研互助交流网站

语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;VScode 前端nodejsvueelementui,该系统采用vue技术和B/S结构进行开发设计&#xff0c;后台使用MySQL数据库进行数据存储。系统主要分为两大模…

Unity框架学习--5 事件中心管理器

作用&#xff1a;访问其它脚本时&#xff0c;不直接访问&#xff0c;而是通过发送一条“命令”&#xff0c;让监听了这条“命令”的脚本自动执行对应的逻辑。 原理&#xff1a; 1、让脚本向事件中心添加事件&#xff0c;监听对应的“命令”。 2、发送“命令”&#xff0c;事件…

低压系统浪涌保护器的综合应用方案

低压系统浪涌保护器&#xff08;Surge Protective Device&#xff0c;SPD&#xff09;是一种用于限制瞬态过电压和导引泄放电涌电流的非线性防护器件&#xff0c;用以保护耐压水平低的电器或电子系统免遭雷击及雷击电磁脉冲或操作过电压的损害。SPD的应用可以有效提高低压系统的…

首发 | FOSS分布式全闪对象存储系统白皮书

一、 产品概述 1. 当前存储的挑战 随着云计算、物联网、5G、大数据、人工智能等新技术的飞速发展&#xff0c;数据呈现爆发式增长&#xff0c;预计到2025年中国数据量将增长到48.6ZB&#xff0c;超过80%为非结构化数据。 同时&#xff0c;数字经济正在成为我国经济发展的新…

怎么使用手机远程控制Win10电脑?

可以使用手机远程控制电脑吗&#xff1f; “近期&#xff0c;我将出差一段时间。问题是&#xff0c;我希望能够从很远的地方浏览家里电脑上的一些东西&#xff0c;但我不会一直随身携带笨重的笔记本电脑。我可以手机远程访问Windows电脑吗&#xff1f; ” 当然&am…

亚马逊feedback和review有什么区别

在亚马逊上&#xff0c;"Feedback"&#xff08;反馈&#xff09;和"Review"&#xff08;评论&#xff09;是两个不同的概念&#xff0c;它们在购物体验中起着不同的作用。 Feedback&#xff08;反馈&#xff09;&#xff1a; 亚马逊的"Feedback"…

Jay17 2023.8.14日报 即 留校集训阶段性总结

8.14 打了moeCTF&#xff0c;还剩一题ak Web。 Jay17-集训结束阶段性总结&#xff1a; 集训产出&#xff1a; 自集训开始以来一个半月&#xff0c;最主要做的事情有三。 一是跟课程&#xff0c;复习学过的知识&#xff0c;学习新的知识&#xff1b;目前课程已大体听完&…

QGIS3.28的二次开发九:添加矢量要素

对矢量要素的编辑是 GIS 软件很重要的功能点之一&#xff0c;也是最难实现的功能点之一。编辑矢量要素涉及到很多方面的考虑&#xff0c;包括且不限于矢量要素的几何类型&#xff0c;拓扑关系&#xff0c;构成要素的节点的增删改&#xff0c;编辑会话 (session) 的启动、回溯和…

Tuxera NTFS Mac2023最新免费版Mac读写工具

有时候我们在使用苹果笔记本的时候&#xff0c;会遇到一些问题&#xff0c;比如怎么打开移动硬盘&#xff0c;或者为什么苹果电脑读不出U盘。这些问题可能让我们感到困惑和沮丧&#xff0c;但其实都有解决办法。本文就来为大家介绍一下苹果笔记本怎么打开移动硬盘和苹果电脑读不…

MRO数字化帮助企业实现明显降本增效

MRO&#xff08;Maintenance, Repair and Operations&#xff09;数字化是指将传统的维修、保养和运营管理过程数字化&#xff0c;以提高效率、降低成本、提高质量和可靠性。MRO数字化是企业数字化转型的重要抓手之一&#xff0c;因为它可以帮助企业实现明显的降本增效。 MRO数…

CSS变形与动画(二):perspctive透视效果 与 preserve-3d 3d效果(奥运五环例子)

文章目录 perspective 3d透视效果preserve-3d 3d嵌套效果例子 奥运五环 backface-visibility 背面效果 perspective 3d透视效果 perspective 指定了观察者与 z0 平面的距离&#xff0c;使具有三维位置变换的元素产生透视效果。z>0 的三维元素比正常大&#xff0c;而 z<0 …

WMS系统库存锁定:提升物流管理效率

一、库存锁定的概念 库存锁定是WMS系统中的一个重要功能&#xff0c;它在物流运作过程中发挥着关键的作用。库存锁定是指在物流流程中&#xff0c;将特定的库存数量或者位置与订单或任务相关联&#xff0c;以确保这些库存不会在未经授权的情况下被其他操作所改变或消耗。库存锁…

「2024」预备研究生mem-论证推理强化:引入前提(上)

一、引入前提&#xff08;上&#xff09; 二、课后练习

DP——背包问题

DP——背包问题 01背包问题分数背包问题多重背包问题完全背包问题 当我们谈论背包问题时&#xff0c;可以想象成一个小朋友要去旅行&#xff0c;但是他只能带一个容量有限的背包。他有一些物品可以选择放入背包&#xff0c;每个物品都有自己的重量和价值。小朋友的目标是在不超…

安卓逆向 - 某麦网 x-mini-wua x-sgext x-sign x-umt x-utdid

本文仅供学习交流&#xff0c;只提供关键思路不会给出完整代码&#xff0c;严禁用于非法用途&#xff0c;若有侵权请联系我删除&#xff01; 目标app: 5aSn6bqm572ROC41LjQ 目标接口&#xff1a;aHR0cHM6Ly9hY3MubS50YW9iYW8uY29tL2d3L210b3AuZGFtYWkud2lyZWxlc3MuZGlzY292ZX…

【历史上的今天】8 月 15 日:苹果推出初代 iMac;谷歌收购摩托罗拉移动;Fuchsia 首次发布

整理 | 王启隆 透过「历史上的今天」&#xff0c;从过去看未来&#xff0c;从现在亦可以改变未来。 今天是 2023 年 8 月 15 日&#xff0c;在 1878 年的今天&#xff0c;我国第一套邮票发行。中国是一个文明古国&#xff0c;在邮政通信方面&#xff0c;有着悠久的历史。早在三…

C语言实例_和校验算法

一、算法介绍 和校验&#xff08;Checksum&#xff09;是一种简单的纠错算法&#xff0c;用于检测或验证数据传输或存储过程中的错误。它通过对数据进行计算并生成校验和&#xff0c;然后将校验和附加到数据中&#xff0c;在接收端再次计算校验和并进行比较&#xff0c;以确定…