【C语言进阶(七)】自定义类型--结构体,位段,联合

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

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C语言学习分享⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习更多C语言知识
  🔝🔝


【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言


1. 前言

文章目标:

本篇文章着重给大家讲解:
结构体内存对齐的知识
并且介绍位段,联合的内容
最后对这一板块做出拓展

结构体,位段和联合
这哥几个的区别和关联到底是什么?

【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言


2. 结构体内存大小问题

首先看下面这段代码:

struct S1
{
	 char c1;
	 int i;
	 char c2;
};

struct S2
{
	 char c1;
	 char c2;
	 int i;
};

这两个结构体中存放的都是
两个char类型和一个int类型数据
所以暂时推断出它们所占内存空间相同

那它们占了多大的空间呢?
char+char+int ,1+1+4=6
我们推断出它至少占6个字节

来验证一下:

printf("%d\n",sizeof(struct S1));
printf("%d\n",sizeof(struct S2));

【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言

结果很出乎意料,它们不仅内存不相同
并且和我们推断出的6也没有太大关系!


3. 结构体内存对齐规则

出现以上原因是因为:
结构体有特殊的内存对齐规则:


3.1 偏移量的概念

在这儿之前先介绍偏移量的概念:

【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言


3.2 内存对齐规则

对齐规则:

  1. 第一个成员在偏移量为0的地址处
  2. 其他成员要对齐到对齐数的整数倍处
  3. 结构体总大小为成员中最大对齐数的整数倍

对齐数概念:

对齐数 = min(编译器默认的对齐数 , 该成员大小)

  • VS中默认对齐数为8
  • linux中对齐数就是成员自身大小

比如在VS编译环境下:

struct S3
{
	double d;
	char c;
	int i;
};
  • d的大小是8,默认对齐数是8,对齐数就是8
  • c的大小是1,默认对齐数是8,对齐数就是1
  • i的大小是4,默认对齐数是8,对齐数就是4

3.3 内存对齐规则实例分析

拿上面的例子来分析

struct S3
{
  double d;
  char c;
  int i;
};

已知:d的对齐数为8
c的对齐数位1
i的对齐数为4
结构体最大对齐数为8

可得:

【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言

对于图片的解释:

  1. d是第一个成员,所以它直接放在
    偏移量为0的位置
  1. c是第二个成员,它的对齐数是1
    任何一个数都是1的倍数,所以
    c紧接着放在d内存的后面
  1. i 是第三个成员,它的对齐数是4
    而c的后面是9, 9不是4的倍数
    10也不是4的倍数,直到12才是
    4的倍数,所以i从12开始放
  1. 最后一个成员放完后的位置是15
    而结构体最大对齐数是8
    15不是8的倍数,16才是
    所以最终在16停止

3.4 回头验证最初的数据

最开始的两个结构体:

struct S1
{
	char c1;
	int i;
	char c2;
};

struct S2
{
	char c1;
	char c2;
	int i;
};

1. 对于S1而言是这样的情况:

【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言

这也就解释清楚为什么会打印12出来的

对于S2而言是这样的情况:

【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言
占8个字节也解释清楚了!


4. 存在内存对齐规则的原因

  1. 原因1:平台原因(移植原因):

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

  1. 原因2:性能原因

如果不存在内存对齐的话
平台4个字节4个字节的访问
int类型的数据时有可能需要
读取两次才能取到一个数据

总的来说:内存对齐是拿空间换取时间

  1. 节省空间的技巧:

发现同样的成员类型和数量
成员放的位置不同,结构体大小
也存在的很大的区别

在写结构体时尽量将占用空间
小的数据集中在一起能节省空间


5. 位段

位段和结构的声明非常相似
但又存在下面这两个不同:

  1. 位段的成员必须是整型家族(int/char)
  2. 位段的成员名后边有一个冒号和一个数字

比如:定义一个位段

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

这个位段的大小是多少呢?
肯定不会是4×4=16个字节这么简单

printf("%d\n",sizeof(struct A));

【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言

结果是8,我们来简单分析一下:


5.1 位段的内存分配规则

位段是具有不确定性的,不能跨平台
它在每一个编译器下可能有所不同

我只介绍在VS编译器下的具体规则:

先初始化一下结构体:

s.a = 3;
s.b = 12;
s.c = 3;
s.d = 4;

冒号后面的数字代表
变量所占的二进制位(比特位)

画图解释:

【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言


6. 联合(共用体)

联合也是一种自定义类型
它其中的变量共用同一份空间!

它的不同:

  1. 成员共用同一份空间
  2. 不用struct定义,而是用union定义
  3. 联合的大小至少是最大成员的大小

比如:

union Un
{
  int i;
  char c;
};
union Un un;//定义联合变量
printf("%d\n", &(un.i));//它们的地址相同
printf("%d\n", &(un.c));//共用同一份空间

【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言


6.1 联合大小计算

联合共用体和结构体一样
有内存对齐原则,不过联合的比较简单:

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

比如:下面这两个联合

union Un1
{
   char c[5];
   int i;
};

union Un2
{
   short c[7];
   int i;
};

printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));

它们的大小分别是:8和16

【C语言进阶(七)】自定义类型--结构体,位段,联合,c语言从入门到精通,c语言,开发语言


7. 总结以及拓展

结构体的内存对齐是面试的常考点!
掌握它不仅可以更深层次了解C语言
还可以在面试的时候给面试官一个震撼

拓展:修改默认对齐数

C语言提供了#pragma指令
来帮助我们解决这个问题:

假设我们想要将默认对齐数改为1:

#pragma pack(1)//设置默认对齐数为1

struct S1
{
  char c1;
  int i;
  char c2;
};

假设我们又想修改回来:

#pragma pack(1)//设置默认对齐数为1
struct S1
{
  char c1;
  int i;
  char c2;
};

#pragma pack()//取消设置的默认对齐数,还原为默认

struct S2
{
  char c1;
  int i;
  char c2;
};

上述代码中,结构体S1
使用的是默认对齐数为1
而S2使用的默认对齐数是8


拓展:利用联合求大小端

详细可以参考以下这篇文章:
利用联合体判断机器大小端文章来源地址https://www.toymoban.com/news/detail-554199.html


🔎 下期预告:动态内存管理 🔍

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

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

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

相关文章

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

    前言 作者简介: 热爱跑步的恒川 ,正在学习C/C++、Java、Python等。 本文收录于 C语言进阶 系列,本专栏主要内容为数据的存储、指针的进阶、字符串和内存函数的介绍、自定义类型结构、动态内存管理、文件操作等,持续更新! 相关专栏Python,Java等正在发展,拭目以待!

    2023年04月14日
    浏览(60)
  • 进阶C语言——自定义类型:结构体,枚举,联合

    结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。 例如描述一个学生: 也可以写成下面这样: 在声明结构的时候,可以不完全的声明。 比如: 上面的两个结构在声明的时候省略掉了结构体标签(tag)。 那么问题来了? 在上面代码的基础

    2023年04月09日
    浏览(32)
  • 【C语言进阶】自定义类型:结构体,枚举,联合

    1.1结构体类的基础知识 结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。 1.2结构的声明 例如描述一个学生: 1.3特殊的声明 在声明结构的时候,可以不完全的声明 上面的两个结构在声明的时候省略掉了结构体标签(tag) 当我们使用匿名结

    2024年02月07日
    浏览(31)
  • 【C语言进阶】自定义类型之结构体,枚举和联合

    人一能之,己百之;人十能之,己千之。                             ——《中庸》   目录 一.结构体 1.结构的基础知识 2.结构体的声明 3.结构体成员的类型 4.结构体变量的定义和初始化: 5.结构体成员的访问: 6.结构体传参  7.结构体内存对齐:结构体的大小 8.为什么要

    2023年04月23日
    浏览(34)
  • C/C++之自定义类型(结构体,位段,联合体,枚举)详解

    专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶 C语言刷题 欢迎大家点赞,评论,收藏。 一起努力,一起奔赴大厂。 目录 个人主页:点我进入主页   1.前言 2.结构体 2.1结构体声明 2.2结构体初始化 2.3结构体的自引用 2,4结构体的内存

    2024年02月08日
    浏览(29)
  • 【C语言:自定义类型(结构体、位段、共用体、枚举)】

    C语言已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类型还是不够的, 假设我想描述学生,描述⼀本书,这时单⼀的内置类型是不⾏的。描述⼀个学生需要名字、年龄、学号、身高、体重等;描述⼀本书需要作者、出版社、定价等。C语言为

    2024年02月05日
    浏览(34)
  • 【无标题】自定义类型:位段,枚举,联合

    在结构体进阶中,我们详细介绍过了结构体。 接下来就是结构体实现位段的功能。 位段的声明和结构是类似的,但有两个不同: ①: 位段的成员必须是int、unsigned int或signed int。 ②: 位段的成员名后边有一个冒号和一个数字。 比如: A就是一个位段类型! 那位段A的大小是

    2024年02月15日
    浏览(30)
  • 【C语言】自定义类型详细讲解(结构体、位段的简单到深入)

    目录 1.结构体的声明 1.1基础知识 1.2结构体的声明 1.3结构体的特殊声明  1.4结构体的自引用 1.5结构体变量的定义和初始化 1.6结构体内存对齐 那对齐这么浪费空间,为什么要对齐  1.7修改默认对齐数 1.8结构体传参 2.位段 2.1什么是位段 2.2位段的内存分配 深入研究VS环境下的位

    2023年04月21日
    浏览(31)
  • 【C语言】自定义类型:结构体深入解析(三)结构体实现位段最终篇

    本小节,我们将学习结构体最后的知识:结构体实现位段,阿森将会和你一起去学习什么是位段?位段的内存分配, VS 怎么开辟位段空间呢?位段跨平台问题,随即位段的应用,最后我们也要了解它的注意事项。文章干货满满,很容易理解,学习起来吧!😊 位段是C语言中结

    2024年02月04日
    浏览(22)
  • C语言进阶——自定义类型:枚举、联合

    🌇个人主页:_麦麦_ 📚今日名言:如果不去遍历世界,我们就不知道什么是我们精神和情感的寄托,但我们一旦遍历了世界,却发现我们再也无法回到那美好的地方去了。当我们开始寻求,我们就已经失去,而我们不开始寻求,我们根本无法知道自己身边的一切是如此可贵

    2024年01月21日
    浏览(33)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包