【C语言】结构体内存对齐:热门面试话题

请添加图片描述
🔥引言

书接上文,我们了解关于结构体的基本知识,这篇将深入剖析结构体中一个重要的知识点:内存对齐
关于内存对齐是属于热门面试话题,对此单独放在一篇来分享

请添加图片描述

Alt

🌈个人主页:是店小二呀
🌈C语言笔记专栏:C语言笔记
🌈C++笔记专栏: C++笔记

🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅
请添加图片描述

文章目录

  • 一、结构体中内存对齐
    • 1.1 对齐规则
    • 1.2 内存对齐的意义
    • 1.3 #pragma(预处理指令)
      • 1.3.1 pragma相关介绍
      • 1.3.2 #pragma pack(n)修改默认对齐数
  • 二、结构体实现位段
    • 2.1 位段的概念
    • 2.2 位段的内存分配
    • 2.3 位段的跨平台问题
    • 2.4 位段的应用


一、结构体中内存对齐

1.1 对齐规则

  • 结构体第一个成员变量对齐相对于结构体成员地址偏移量为0的位置上

  • 其他成员变量需要对齐到对齐数的整数倍

  • 结构体总大小最大对齐数的正数倍

如果存在嵌套结构体的情况,嵌套结构体占用空间需要对齐自身最大对齐数的整数倍,同时在计算结构体总大小的时候,嵌套结构体的最大对齐数参与比较

注意】:对齐数 == 编译器默认的一个对齐数与该成员变量大小的较小值

  • 在vs环境下,系统默认对齐为8

  • 在Linux中没有默认对齐数,对齐数就是成员自身的大小


通过题目熟练的掌握以上知识.

struct S1
{char c1;int i;char c2;
};
printf("%d\n", sizeof(struct S1));--12struct S2
{char c1;char c2;int i;
};
printf("%d\n", sizeof(struct S2));--8struct S4
{char c1;struct S2 s2;double d;
};
printf("%d\n", sizeof(struct S2));--24

在这里插入图片描述
在这里插入图片描述

说明】:数值代表的是结构体变量地址处的偏移量


1.2 内存对齐的意义

⼤部分的参考资料都是这样说的

平台原因(移植原因)

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

性能原因

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

假设⼀个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。

总体来说:结构体的内存对齐是拿空间来换取时间的做法

!(https://img-blog.csdnimg.cn/direct/db9b7a7f327947f7a81d64a1a2254b68.gif)

通过上述的观察,不难看出。如果不存在内存对齐,需要执行两个内存访问(对象被分放在两块内存块),而内存对齐只需要进行一次。

对此在涉及结构体时,需要考虑满足对齐,又要节省空间。可以将占用空间小的成员尽量集中在一起

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

1.3 #pragma(预处理指令)

1.3.1 pragma相关介绍

  • 用于指定计算机或操作系统特定的编译器功能
  • 根据定义pragma指令是计算机或操作系统特定的,并且通常对于每个编译器而言都有所不同
  • pragma指令可用于条件语句以提供新的预处理器功能,或为编译器提供实现所定义的信息,

1.3.2 #pragma pack(n)修改默认对齐数

#include <stdio.h>
#pragma pack(1)//设置默认对齐数为1
struct S
{char c1;int i;char c2;
};
#pragma pacK()//取消默认对齐数,还原为默认对齐数
int main()
{printf("%d\n",sizeof(struct S));return 0;
}

推荐使用场景,在结构体进行内存对齐时,如果对于对齐方式不能达到预期,可以通过该指令更改默认对齐数

获得该成员变量的偏移量

这里需要使用一个函数offsetof()宏,该函数被声明在stddef.h文件中,以下是函数offsetof()宏

size_t offsetof(type,member);

宏定义】:

#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE*)0)->MEMBER)

如果想要了解更多,可以参考下这篇博客Offsetof宏详解-CSDN博客.这里只如何去使用Offsetof()宏计算出结构体某成员地址的偏移量。

#include <stdio.h>
#include <stddef.h>
struct S
{char a;int i;
};
int main()
{printf("%d\n",offsetof(struct S,i));//那么这里的结果就是就是4return 0;
}

小总结】:
结构体中的内存对齐是为了以空间换取时间的做法,随着计算机不断地更新换代,一般不需要担心内存空间不足的问题,逐渐地从更多考虑的是时间上的问题。同时为了节约空间的开销,提出位段


二、结构体实现位段

2.1 位段的概念

位段是结构体的一种变形,在功能、用法上与结构体基本一致,但是在于内存分配上不同,位段可以很好的节省空间,可存在位段跨平台的问题。同时与结构体相比有两个点不同。

  • 成员上:intunsigned intsigned int,但是在C99中是可以选择其他类型
  • 格式上:位段成员名后面有一个冒号和一个数字
struct A
{char _a:2;char _b:5;
};

【说明】:这里数字代表的是该成员变量占用空间大小,而大小单位是比特

【问题】:位段A所占的内存大小是多大?

这个问题,需要利用下面的知识了


2.2 位段的内存分配

  • 位段成员:intunsigned intsigned int或者char等类型(需要是整形,是要转换为二进制
  • 位段开辟空间的大小一般是以四个字节或一个字节开辟的
  • 位段涉及许多不确定的因素,位段是不跨平台的,注意可移植的程序,应该避免使用位段
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;

2.3 位段的跨平台问题

不确定的因素大致包括】:

  1. 内存存放的方向是从左到右,还是从右到左
  2. 是低地址到高地址,还是高地址到低地址
  3. int类型是不确定是被当作有符号数还是无符号数
  4. 当一个结构体包括了两个位段,第二个位段比较大,无法容纳第一个位段剩下的空间,是舍弃还是利用剩下的空间,这是不确定的
  5. 位段中最大位的数目不能确定(16位机器最大16,32位机器最⼤32,写成27,在16位机器会出问题),可能会冲出最大的范围,出现问题

我们不妨以vs2013环境下测量下数据

vs2013下,位段是从左到右,从低地址到高地址,位段需要的空间不足,直接开辟一块新的空间,我们来结合图片理解下

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

【步骤】:

  1. 位段开辟八个bit位(这里是char类型的情况)
  2. 位段成员后面数字是占用多少bit位
  3. 根据变量数据,转化为二级制(一个二级制为一个比特位),根据位段对应的数据,将转为的二级制多个比特位放入
  4. 关于上不确定因素中(4),vs2013选择舍弃,那就开辟一块新的空间,重复(1,2,3)步骤

2.4 位段的应用

比如下图中网络协议中,在一个结构存在很多只需要几个bit位就能实现的效果,这里使用位段就能达到想要的效果,也能节省空间的浪费。同时网络传输的数据大小也会小一点,提高了网络的流畅和效率!

位段使用注意事项】:

struct A
{int _a:2;int _b:5;
};
int main()
{//错误的做法struct A s={0};scanf("%d",&s._a);//正确的示范int b=0;scanf("%d",&b);s._b=b;return 0;
}

说明】:

位段的几个成员共有同一个字节,而有些成员的起始位置并不是某个字节的起始位置。对此这些位置是没有地址(内存中每个字节分配一个地址,一个字节内部的bit位是没有地址的

解决办法】:

可以将值放入一个变量中,再通过赋值给位段成员,这个赋值在以后的操作中,是很巧妙的用法的。


在这里插入图片描述
以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二C语言笔记,希望对你在学习C语言中有所帮助!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker Portainer使用

Portainer是什么 Docker Portainer是一个轻量级的 Web UI 管理界面,可以用来管理Docker环境。它提供了一个直观的控制台,用户可以通过它来管理Docker主机、容器、网络、卷等Docker资源。 Portainer的主要功能和特点包括: 容器管理:可以查看、启动、停止、删除容器,以及查看容器…

计算机毕业设计 | springboot+vue房屋租赁管理系统(附源码)

1&#xff0c;绪论 1.1 课题来源 随着社会的不断发展以及大家生活水平的提高&#xff0c;越来越多的年轻人选择在大城市发展。在大城市发展就意味着要在外面有一处安身的地方。在租房的过程中&#xff0c;大家也面临着各种各样的问题&#xff0c;比如需要费时费力去现场看房&…

host修改

前言 想要修改 hosts 文件&#xff0c;您需要具有对系统文件的适当访问权限&#xff0c;并且知道如何编辑文本文件。hosts 文件是一个用于域名解析的本地文件&#xff0c;它允许您为特定的 IP 地址指定主机名。 以下是在不同操作系统中修改 hosts 文件的步骤&#xff1a; 一、…

项目集成SkyWalking,基于k8s搭建

一、搭建SkyWalking 官方文档&#xff08;英文&#xff09;&#xff1a;skywalking/docs at master apache/skywalking 中文可以使用&#xff1a;GitHub - SkyAPM/document-cn-translation-of-skywalking: [已过期,请使用官网AI文档] The CN translation version of Apache…

【qt】自定义代理类

自定义代理类 一.应用场景二.创建自定义代理类1.创建一个类2.共有继承父类3.添加宏4.初始化父类5.拿到我们需要重写的虚函数 三.实现父类的4个虚函数1.创建代理组件2.设置代理组件数据3.设置模型数据4.跟新代理组件的位置 四.使用代理类1.头文件2.私有成员3.视图设置代理 五.其…

Web上机:JSP+Servlet+JDBC的交互流程

目录 需求与设计 基础需求&#xff1a; 项目结构&#xff1a; 项目逻辑&#xff1a; 运行图示&#xff1a; 代码实现 Login.jsp InsertServlet SelectServlet Table.jsp user mysql表结构 Web开发技术迭代速度日新月异&#xff0c;对于技术的更新往往是基于底层一…

基于Python+flask+echarts的气象数据采集与分析系统,可实现lstm算法进行预测

背景 基于PythonFlaskEcharts的气象数据采集与分析系统结合了强大的数据处理能力和可视化展示技术&#xff0c;旨在实现对气象数据的实时采集、存储和分析。通过Python编程语言实现数据采集模块&#xff0c;利用Flask框架搭建后端系统&#xff0c;实现数据处理、存储和分析功能…

Python小游戏——俄罗斯方块

文章目录 项目介绍环境配置代码设计思路1.初始化和导入库&#xff1a;2.定义颜色和屏幕尺寸&#xff1a;3.定义游戏逻辑&#xff1a;4.游戏循环&#xff1a; 源代码效果图 项目介绍 俄罗斯方块游戏是一款经典的益智游戏&#xff0c;玩家通过旋转和移动各种形状的方块&#xff…

深入剖析—【服务器硬件】与【Nginx配置】:从基础到实战

服务器硬件部分&#xff1a; Processor (CPU)&#xff1a;服务器的计算核心&#xff0c;负责处理数据和执行程序。Memory (RAM)&#xff1a;用于暂时存储和快速访问数据&#xff0c;决定了系统的运行速度和并发处理能力。Storage (HDD/SSD)&#xff1a;长期存储数据的设备&…

爱设计AiPPT.cn赵充:营销工作的AI进化

爱设计&AiPPT.cn是一家 AIGC 数字科技企业&#xff0c;致力于打造「下一代个人与组织的 Ai 工作站」 。目前旗下产品包括AiPPT.cn、爱设计AIGC 内容中台、365 编辑器、爱设计在线设计工具、AiH5 等超过 10 余款应用 AI 能力的内容创作工具。日前&#xff0c;爱设计&AiP…

期货学习笔记-横盘行情学习1

横盘行情的特征及分类 横盘行情的概念 横盘行情时中继形态的一种&#xff0c;一般常出现在大涨或大跌之后出现横盘行情是对当前趋势行情的修正&#xff0c;是对市场零散筹码的清理&#xff0c;是为了集中筹码更便于后期行情的展开 横盘行情的特征 1.水平运动&#xff1a;该…

从零自制docker-15-【实现 mydocker run -d 支持后台运行容器】

文章目录 实现目的莫名奇妙的问题对之前upper层出现root补充对run某些命令出现找不到文件或目录的原因代码效果 实现目的 docker run -d时容器在后台运行&#xff0c;而不会进入命令行交互形式 首先是需要添加-d选项然后设置当添加-d选项时候主进程不会等待子进程&#xff0c…

从Python代码到pip包:打包Python项目

大家好&#xff0c;在软件开发的世界中&#xff0c;共享和重用代码是至关重要的。Python社区为我们提供了丰富的资源&#xff0c;使得我们能够轻松地与他人分享我们的工作&#xff0c;并从他人的工作中受益。将代码打包成pip包&#xff08;Python包管理器&#xff09;是一种常见…

Moto和Inter字节序

inter: 低地址按照start_bit位放低字节依次往高字节填充 MotoLsb: 低地址按照start_bit位放高字节&#xff0c;依次往低字节填充MotoMsb&#xff1a;高字节按照start_bit位放低地址&#xff0c;依次往高字节填充

uni-app实现页面之间的跳转传参(八)

界面之间的参数传递在 开发中经常会用到,这节主要将一下uni-app开发应用是的传参情况。如下图所示,我的一级界面将点检分成三类:日点检、周点检和年保养;在点击相应的会导航到相应的功能。 在uni-app中常用的方法有uni.navigateTo(OBJECT)、uni.redirectTo(OBJECT);简单的…

怎么图片转excel表格免费?介绍三个方法

怎么图片转excel表格免费&#xff1f;在日常工作中&#xff0c;我们经常需要将图片中的表格数据转化为可编辑的Excel格式。幸运的是&#xff0c;市面上有多款软件支持这一功能&#xff0c;并且部分软件还提供免费使用的选项。本文将为您详细介绍几款可以免费将图片转换为Excel表…

Flink DataStream API 介绍

一、介绍 官网 DataStream API 得名于特殊的 DataStream 类&#xff0c;该类用于表示 Flink 程序中的数据集合。你可以认为 它们是可以包含重复项的不可变数据集合。这些数据可以是有界&#xff08;有限&#xff09;的&#xff0c;也可以是无界&#xff08;无限&#xff09;的…

快速排序算法备考

快排模板 快速排序(快排) (C语言实现)_c语言快速排序_Brant_zero2022的博客-CSDN博客 快排使用递归来实现 关键思想:划分 //划分 int partion(int A[],int L,int R){int midA[L];while(L<R){//每一次划分:左边元素<枢轴元素<右边元素//R往前找&#xff0c;直到找到一…

IO系列(八) -浅析NIO工作原理

一、简介 现在使用 NIO 的场景越来越多&#xff0c;很多网上的技术框架或多或少的使用 NIO 技术&#xff0c;譬如 Tomcat、Jetty、Netty&#xff0c;学习和掌握 NIO 技术已经不是一个 Java 攻城狮的加分技能&#xff0c;而是一个必备技能。 那什么是 NIO 呢&#xff1f; NIO…

不拍视频,不直播怎么在视频号卖货赚钱?开一个它就好了!

大家好&#xff0c;我是电商糖果 视频号这两年看着抖音卖货的热度越来越高&#xff0c;也想挤进电商圈。 于是它模仿抖音推出了自己的电商平台——视频号小店。 只要商家入驻视频号小店&#xff0c;就可以在视频号售卖商品。 具体怎么操作呢&#xff0c;需要拍视频&#xf…