【C语言】结构体内存布局解析——字节对齐
🦄个人主页:小米里的大麦-CSDN博客
🎏所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html
🎁代码托管:黄灿灿 (huang-cancan-xbc) - Gitee.com
⚙️操作环境:Visual Studio 2022
目录
一、引言
二、什么是字节对齐?
三、字节对齐规则
1. 成员对齐规则:
2. 结构体整体对齐规则:
3. 编译器依赖性:
小结
四、示例分析
内存布局
示例一:简单结构体
示例二:复杂对齐规则
示例三:自定义对齐方式
思考:(自行尝试一下吧)
五、如何自定义对齐方式
使用#pragma pack
使用__attribute__((packed))
六、总结
共勉
一、引言
在C语言中,结构体是一种用户定义的数据类型,一种非常有用的数据类型,它允许程序员将不同类型的数据组织在一起。结构体的大小并不是简单地等于所有成员变量大小之和,因为编译器会对结构体中的数据进行字节对齐(byte alignment),以优化访问速度。理解结构体在内存中的布局对于编写高效且可维护的代码至关重要。本文将探讨结构体内存布局的基本原理。
二、什么是字节对齐?
字节对齐是指数据在内存中的存储方式,以提高内存访问效率。大多数现代计算机系统在内存访问时,要求数据地址满足特定的对齐条件,否则可能会导致访问效率下降,甚至是硬件异常。
具体来说,数据的对齐要求是由其数据类型决定的。例如,4字节的整型变量通常要求其地址是4的倍数。结构体中的每个成员也必须满足其对齐要求。
对齐规则通常由编译器和处理器架构共同决定。常见的规则包括:
- 自然对齐:数据类型应该按照它的自然对齐要求放置。例如,一个
int
类型(假设为4字节)应该放在4字节对齐的位置上。- 最大对齐:结构体或联合中的所有成员都将按照最大成员的对齐要求进行对齐。
- 固定对齐:有时编译器会强制所有成员按某个固定的对齐值进行对齐。
三、字节对齐规则
1. 成员对齐规则:
- 每个成员会根据其类型自动对齐到一个特定的字节边界。例如,
char
类型通常不需要对齐,而int
可能需要 4 字节对齐。- 如果一个成员的偏移量不是其大小的倍数,则会在前面填充空字节以满足对齐要求。也就是浪费空间(以空间换时间)。
- 内存地址是从0开始递增的,因此在内存中,每个字节都有一个唯一的地址,这些地址是从0开始编号的。(这非常重要!!!)
2. 结构体整体对齐规则:
- 结构体自身也有一个对齐要求,通常是最大成员的对齐要求。这意味着整个结构体的大小必须是这个对齐值的倍数。
- 第一个成员在与结构体变量偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
- 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
- VS中默认的值为8
- 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
3. 编译器依赖性:
- 不同的编译器可能有不同的默认对齐规则,这些规则可以通过预处理器宏或命令行选项来更改。(以VS为例,通常vs是以8字节对齐)
4. 小结
- 成员的排列顺序:结构体成员按照声明的顺序依次存放。
- 对齐方式:每个成员按照自身类型的对齐要求对齐。
- 地址编号:内存地址从0开始编号。
- 结构体的总大小:结构体的总大小必须是其最宽基本类型成员大小的倍数(即结构体的对齐方式)。
四、示例分析
下面通过几个例子来具体说明结构体大小的计算过程。
首先,让我们定义一个简单的结构体
S
,它包含了三个成员:一个整型变量a
、一个字符数组c
以及一个双精度浮点数d
。
struct S {int a;char c[5];double d;
};
这个结构体中包含的不同数据类型需要不同数量的字节来存储:int a: 假设在32位系统上,int通常占用4个字节。
char c[5]: 每个char占用1个字节,加上数组长度为5,因此占用5个字节。
double d: 在大多数系统上,double占用8个字节。
内存布局
当我们在程序中声明一个
S
类型的变量时,例如:struct S s;
编译器会为这个结构体分配连续的内存空间,并按照成员出现的顺序依次存放它们。
- 整型变量
a
:占据前4个字节。- 字符数组
c
:紧接着a
后面,占据接下来的5个字节。- 双精度浮点数
d
:位于字符数组之后,占据了剩余的8个字节。这意味着整个结构体
S
在内存中所占的空间为4 + 5 + 8 = 17个字节。(以8字节对齐,从0开始,最后的一个字节处于 ‘地址16’ 的位置,16刚好是8的倍数,不用增加,大小刚刚好)
请注意,由于不同的编译器可能有不同的内存对齐策略,因此实际的内存布局可能会有所不同。一些编译器会对结构体成员进行填充,以确保某些类型的对齐要求被满足。这种对齐可以帮助提高数据访问的速度,但也可能导致结构体的实际大小大于简单计算得出的大小。
示例一:简单结构体
struct Example1 {char a;int b;short c;
};
我们逐一分析这个结构体的内存布局:char a,大小为1字节,对齐要求为1字节。
int b,大小为4字节,对齐要求为4字节。为了满足对齐要求,在char a之后需要3字节的填充。
short c,大小为2字节,对齐要求为2字节。int b之后无需填充。
内存布局如下:
| a(1) | 填充(3) | b(4) | c(2) | 填充(2) |
结构体的总大小应是最大对齐要求的倍数,这里是4的倍数,所以最终大小为12字节。
示意图(这样表示只是便于观察,其实并不准确,大概知道内存中是怎样存储即可!!):
| a | - | - | - | b | b | b | b | c | c | - | - | ————存储0 1 2 3 4 5 6 7 8 9 10 11 ————地址编号
示例二:复杂对齐规则
struct Example2 {double a;char b;int c;
};
内存布局分析:double a,大小为8字节,对齐要求为8字节。
char b,大小为1字节,对齐要求为1字节。double a之后需要7字节的填充。
int c,大小为4字节,对齐要求为4字节。char b之后需要3字节的填充。
内存布局如下:
| a(8) | b(1) | 填充(7) | c(4) | 填充(4) |
结构体的总大小应是最大对齐要求的倍数,这里是8的倍数,所以最终大小为24字节。
示意图如下:
| a | a | a | a | a | a | a | a | b | - | - | - | - | - | - | - | c | c | c | c | - | - | - | - |
示例三:自定义对齐方式
#pragma pack(1)
struct Example3 {char a;int b;short c;
};
#pragma pack()
通过设置
#pragma pack(1)
,我们取消了默认的对齐要求,结构体大小变为:| a(1) | b(4) | c(2) |
总大小为7字节。
示意图如下:
| a | b | b | b | b | c | c |
思考:(自行尝试一下吧)
这里是原代码,尝试一下吧~
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>struct S1
{char c1;int i;char c2;
}S1;
struct S2
{char c1;char c2;int i;
}S2;int main()
{printf("%d\n", sizeof(S1));printf("%d\n", sizeof(S2));return 0;
}
五、如何自定义对齐方式
在某些情况下,我们可以使用
#pragma pack
指令或__attribute__((packed))
来改变默认的对齐方式。
使用
#pragma pack
#pragma pack(1) struct Packed {char a;int b;short c; }; #pragma pack()
通过设置
#pragma pack(1)
,我们取消了默认的对齐要求,结构体大小变为:| a(1) | b(4) | c(2) |
总大小为7字节。
使用
__attribute__((packed))
struct Packed {char a;int b;short c; } __attribute__((packed));
与
#pragma pack(1)
效果相同,总大小也是7字节。
六、总结
理解结构体的内存对齐规则对于优化内存使用和提高程序性能非常重要。以下是一些关键点:
- 结构体成员按声明顺序排列,满足自身对齐要求。
- 结构体总大小是其最大对齐要求的倍数。
- 可以使用
#pragma pack
或__attribute__((packed))
自定义对齐方式。- 地址编号:内存地址从0开始编号。
- 对齐规则:数据类型应该按照其大小的倍数对齐。
- 填充:为了满足对齐要求,编译器可能会在结构体中插入空隙(填充)。
通过这些规则和技巧,我们可以更好地设计和使用C语言中的结构体。希望本文对您理解结构体大小计算和字节对齐有所帮助。
共勉
相关文章:
【C语言】结构体内存布局解析——字节对齐
🦄个人主页:小米里的大麦-CSDN博客 🎏所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html 🎁代码托管:黄灿灿 (huang-cancan-xbc) - Gitee.com ⚙️操作环境:Visual Studio 2022 目录 一、引言 二、什么是字节对齐&…...
模型表达方式
目录 一、模型表达概述 二、模型精确表达 2.1 几何表示 (Geometrical Representation) 三、模型非精确表达 3.1 网格表示 (Mesh Representation) 3.2 体素表示 (Voxel Representation) 一、模型表达概述 模型的表达方式多种多样,选择适合的表达方式取决于具体应用场景和…...
校园课程助手【4】-使用Elasticsearch实现课程检索
本节将介绍本项目的查询模块,使用Elasticsearch又不是查询接口,具体流程如图所示(如果不了解Elasticsearch可以使用sql语句进行查询): 这里是两种方法的异同点: Mysql:擅长事务类型操作&#…...
经典运维面试题
1、Linux常见的日志文件都有哪些,各自的用途?日志轮询配置文件在哪里?欢迎界面配置文件在哪里? /var/log/messages #内核及公共消息日志/var/log/cron #计划任务日志/var/log/dmesg #系统引导日志/var/log/malilog #邮件系…...
别再盲目推广了!Xinstall助你开启App线下推广新篇章
在这个数字化飞速发展的时代,App已经成为我们生活中不可或缺的一部分。然而,App市场的竞争也日益激烈,如何让你的App在众多竞争者中脱颖而出,成为每个推广者必须面对的问题。今天,就让我们一起探讨一下App线下推广的痛…...
大厂linux面试题攻略五之数据库管理
一、数据库管理-MySQL语句 0.MySQL基本语句: 1.SQL语句-增 创建xxx用户: mysql>create user xxx % indentified by 123456; xxx表示用户名 %b表示该用户用来连接数据库的方式(远程或本地连接) indentified by 123456设置密码…...
【pytorch】模型集成
在集成学习中,我们会训练多个模型(通常称为「弱学习器」)解决相同的问题,并将它们结合起来以获得更好的结果。最重要的假设是:当弱模型被正确组合时,我们可以得到更精确和/或更鲁棒的模型。 常用的模型集成…...
初识集合和数据结构
目录 初识集合框架数据结构基本概念和术语数据数据元素数据项数据对象前四者的关系数据结构逻辑结构和物理结构逻辑结构物理结构 算法算法设计要求 初识集合框架 Java的集合框架也可被称为容器,是定义在Java.util包下的一些接口和实现类。其就是将多个元素存储到一…...
cocos creator 3.x中动态加载 resources 文件夹下的图片时提示找不到
文件目录如下 类型为spriteFrame 代码案例 图片设置为 sprite-frame、texture 或其他图片类型后,将会在 资源管理器 中生成一个对应类型的资源。但如果直接加载 equipments/testea,得到的类型将会是 ImageAsset,必须指定路径到具体的子资源…...
第九十八周周报
学习时间: 2024.7.27-204.8.3 学习产出: 这周主要在按照审稿人的意见修改论文,由于有个模型保存的文件找不到了,所以重新训练花了点时间,目前已经把修改后的论文和cover letter发给杨老师了。...
程序员找工作之数据结构面试题总结分析
文章目录 1. 数据结构的基本概念与分类2. 数据结构的存储与表示3. 数据元素的存储与关系4. 存储结构的选择与考量5. 特定数据结构的定义与特性6. 数据结构操作与应用7. 数组与存储8. 特定数据结构的存储与访问 程序员在找工作面试中,数据结构方面可能会被问到的问题…...
设置provider解决maven找不到JUnit 5测试样例
问题描述 尝试复现一个用大模型生成测试样例的工作,但使用maven生成的JUnit 5测试样例死活不执行。又不想用命令行运行,因此进行排查 基本知识 <dependencies> junit-jupiter-api JUnit 5写代码时调用的库 junit-jupyter-engine 运行JUnit 5测…...
php反序列化靶机serial实战
扫描ip,找到靶机ip后进入 他说这是cookie的测试网页,我们抓个包,得到cookie值 base64解码 扫描一下靶机ip的目录 发现http://192.168.88.153/backup/,访问 下载一下发现是他的网页源码 通过代码审计,发现 通过代码审计得知&…...
类型推断技术及仓颉语言实践
史磊 仓颉语言类型推断技术专家 一、一种看待类型系统的方式 一门编程语言一定得包含类型系统吗? 这个问题今天看来可能显而易见,一个程序没有类型的话还能算是个完整、正确的程序吗?但是其实关于类型系统的作用,一直是存在两种…...
职场生存秘籍:16条黄金法则
作者简介:一名计算机萌新、前来进行学习VUE,让我们一起进步吧。 座右铭:低头赶路,敬事如仪 个人主页:我叫于豆豆吖的主页 写在前面 在这个瞬息万变的时代,职场不仅是实现个人价值与梦想的舞台,更是一…...
Flask 介绍
Flask 介绍 为什么要学 Flask框架对比设计哲学功能特点适用场景学习曲线总结 Flask 的特点Flask 常用扩展包Flask 的基本组件Flask 的应用场景官方文档官方文档链接文档内容概述学习建议 Flask 是一个使用 Python 编写的轻量级 Web 应用框架。它旨在让 Web 开发变得快速、简单且…...
JAVA基础知识点3 (String 和 StringBuffer 以及 StringBuilder 的特点以及区别)
1,String 和 StringBuffer 以及 StringBuilder 的特点 (1)String的特点:String是final修饰的字符序列是不可改变的, 是字符串常量,一旦初始化就不可以被更改,因此是线程安全的 因为是常量每次对其操作都会…...
2024年8月AI内容生成技术的现状与未来:从文生文到跨模态交互的全景分析
2024年8月AI内容生成技术的现状与未来:从文生文到跨模态交互的全景分析 大家好,我是猫头虎!🚀 随着AI在内容生成领域的爆发式发展,从2022年末开始,AI生成技术已经走过了文生文(AIGC)…...
File 34
package File;import java.awt.*; import java.io.File;public class file1 {public static void main(String[] args) {//创建FILE对象,指代某个具体的文件//路径分隔符File f1new File("C:/Users/SUI/Desktop/kaishi/nih.txt");// File f1new File(&quo…...
AI全知道-Embedding model中的Vector知识点
在嵌入模型(Embedding Model)中,向量(Vector)是核心概念之一。向量表示法不仅是数学中的基本工具,也是机器学习和深度学习中处理高维数据的关键手段。本文将深入探讨向量在嵌入模型中的作用、表示方法、计算和应用等知识点。 一、向量的基本概念 向量是一个具有方向和大…...
Qt 学习第四天:信号和槽机制(核心特征)
信号和槽的简介 信号和插槽用于对象之间的通信。信号和插槽机制是Qt的核心特征,可能是不同的部分大部分来自其他框架提供的特性。信号和槽是由Qt的元对象系统实现的。介绍(来自Qt帮助文档Signals & Slots) 在GUI编程中,当我们…...
跳跃游戏Ⅱ C++简单代码
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - 1] 的最…...
Gitlab中access token 和Deploy token的区别
在GitLab中,Access Token和Deploy Token是两种不同类型的令牌,用于不同的目的。以下是它们的主要区别: ### Access Token 1. **用途**: - 用于用户身份验证,允许用户以编程方式访问GitLab API。 - 可以用于克隆…...
【多线程】线程的五种创建方法
文章目录 线程在 Java 代码中编写多线程程序Thread 标准库 创建线程的写法1 . 继承 Thread 类代码回调函数休眠操作:sleep()抢占式执行观察线程jconsoleIDEA 内置调试器 2 . 实现 Runnable 接口代码 3. 匿名内部类创建 Thread ⼦类对象代码匿名内部类 4.匿名内部类创…...
关闭窗口工具类 - C#小函数类推荐
此文记录的是一个关于关闭窗口工具类。 /***关闭窗口工具类Austin Liu 刘恒辉Project Manager and Software DesignerE-Mail: lzhdim163.comBlog: http://lzhdim.cnblogs.comDate: 2024-01-15 15:18:00使用方法:CloseWindowUtil.CloseWindow(this.Handle);***/n…...
Xilinx FPGA 原语解析(一):IBUFDS_GTE3 差分时钟输入缓冲器
目录 1.使用说明 2.实例化代码 3.参数解释 4.端口连接 1.使用说明 IBUFDS_GTE3 是Xilinx FPGA 中用于高速接口的差分时钟信号输入缓冲器。 BUFDS_GTEx,x2/3/4(不同系列的FPGA x的值不同),其中UltraScale使IBUFDS_GTE3…...
力扣SQL50 患某种疾病的患者 正则表达式
Problem: 1527. 患某种疾病的患者 在SQL查询中,REGEXP 是用于执行正则表达式匹配的操作符。正则表达式允许使用特殊字符和模式来匹配字符串中的特定文本。具体到你的查询,^DIAB1|\\sDIAB1 是一个正则表达式,它使用了一些特殊的通配符和符号。…...
k8s集群的资源发布方式(滚动/蓝绿/灰度发布)及声明式管理方法
目录 1.常见的发布方式 2.滚动发布 3.蓝绿发布 4.实现金丝雀发布(Canary Release) 5.声明式管理方法 1.常见的发布方式 蓝绿发布:两套环境交替升级,旧版本保留一定时间便于回滚优点:用户无感知,部署和回滚速度较…...
SwiftUI 中掌握 ScrollView 的使用:滚动可见性
文章目录 前言视图修饰符应用场景可见性完整示例ContentViewVideoPlayerViewScrollViewVisibilityApp 总结 前言 我们的滚动 API 中又有一个重要的新增功能:滚动可见性。现在,你可以获取可见标识符列表,或者快速检查并监控 ScrollView 内视图…...
中药养发护发
按照中医理论,头发和肝肾有密切联系,肝主血,肾藏精, 其华在发,肝肾强健,上荣于头,则毛发乌黑浓密. 中药育发的应用 以当归,天麻,桑疹子养血润发,配合干姜祛风活血,能通畅经络, 加快循环,激活毛囊,能促进皮肤组织营养成分吸收和废弃物的排泄,改善 头发生态. 用苦参 皂角 清热化…...
深圳o2o网站建设/网站模板
地址如下:https://github.com/Snailclimb/JavaGuide 星号非常多。是看到最全最细的Java 学习和面试指南了,涵盖了Java基础,并发,JVM,计算机基础等核心知识点,还总结了常用框架,大厂高频面试题和…...
wordpress主题js文件在哪/百度老年搜索
cordova提供官方的push pluging,使用的是Google的GCM消息推送服务,一些网络原因,国内GCM可能不怎么好用。所以选择国内的第三方插件。 可供选择的有百度云推送,腾讯云信鸽,极光推送等,其中只有极光推送官方提供了phone…...
汕头网站公司/今日军事新闻头条
昨天做了什么 设计APP 今天打算做什么 修改错误 遇到的问题 APP中按钮关联错误转载于:https://www.cnblogs.com/liulala2017/p/8185604.html...
做网站建设哪家好/怎么申请网站
This和super都是Java中的关键字,this表示当前对象,可以调用方法、属性、指向对象本身。super表示父类,可以调用父类的方法、属性、对象。This在Java中使用有三种: 第一,指向当前对象 1 package day03;2 3 4 5 publi…...
凡科网站能在百度做推广吗/建网站找哪个公司
Day 1(冯哲) 今天的内容很杂但却都是基础知识 主要分为下面几个点 枚举 枚举也称作穷举,指的是从问题所有可能的解的集合中一一枚举各元素。用题目中给定的检验条件判定哪些是无用的,哪些是有用的。能使命题成立的即为其解。 有几…...
用阳寿做交易的网站/网络推广有哪几种方法
part1:现状分析 某中小企业希望在现有It架构基础之上对当前的DELL服务器进行扩容。 其中一台R610目前有剩余硬盘空间,但是8GB内存已吃满,内存有扩展的空间; 另外一台R710,内存为32GB,有大量剩余内存&#…...