【C语言】结构体内存对齐机制详解

2023-09-22 15:06:04

一、前言

在讲解结构体内存对齐机制之前,我们先来看1个例子:

typedef struct
{
    char sex;       //  性别
    int id;         //  学号
    char name[20];  //  姓名
    float score;    //  成绩
    char addr[30];  //  地址
}STU;

int main(){
    STU student1;
    printf("%d\n",sizeof(student1));//  打印结构体变量所占内存长度
    return 0;
}

以上代码示例中定义了1个结构体student1,包含5个不同数据类型的成员,分别占用内存空间:
char sex:1 Byte
int id:4 Byte
char name[20]:20 Byte
float score:4 Byte
char addr[30]:30 Byte
根据结构体特性,结构体变量所占内存长度等于其各成员所占内存长度之和,因此这里打印的sizeof(student1)是否等于1+4+20+4+30=59呢?运行程序后结果如下:

size of student1: 64

为什么这里结构体变量student1所占内存长度是64而不是59呢?因为有结构体内存对齐机制的存在。这是很多新手程序猿很容易走进的一个误区,接下来我们一起来了解结构体对齐机制。

二、结构体内存对齐规则

  1. 结构体第一个成员的地址即为该结构体变量的地址。
  2. 结构体成员内存对齐时,其存放的内存单元大小为min{有效对齐值,指定对齐值}的最小整数倍。
    注意:
    自身对齐值: 结构体变量里每个成员自身所占内存大小
    指定对齐值: 使用宏定义#pragma pack(N) 其中N的值即为指定对齐值。N必须是2的幂次方,例如:1,2,4,8等,如果没有使用宏定义指定对齐值,则指定对齐值取决于操作系统位数,32位操作系统默认指定对齐值为4,64位操作系统默认指定对齐值为8
    有效对齐值: 有效对齐值为min{自身对齐值,指定对齐值}。
  3. 结构体总占用内存大小为min{成员最大自身对齐值,指定对齐值}的整数倍。

三、实例解析

以下示例代码均在64位Windows操作系统下运行
1、使用默认指定对齐值
使用文章前言的代码分析:

#include <stdio.h>

typedef struct
{
    char sex;       //  性别
    int id;         //  学号
    char name[20];  //  姓名
    float score;    //  成绩
    char addr[30];  //  地址
}STU;

int main(){
    STU student1;
    printf("size of student1: %d\n",sizeof(student1));    //  打印结构体变量所占内存长度
    return 0;
}
成员自身对齐值指定对齐值有效对齐值
sex18min{1,8}
id48min{4,8}
name[20]18min{1,8}
score48min{4,8}
addr[30]18min{1,8}

结构体总体对齐时,应按照成员自身对齐值的最大值的整数倍对齐,这里程序在没有宏定义指定默认对齐值的情况下,对齐值就应该是min{4,8},也就是4字节,这种情况下,该结构体每一个成员开辟的存储空间都为4字节。

成员实际占用内存大小系统开辟内存空间大小
sex14
id44
name[20]2020
score44
addr[30]3032

在这里插入图片描述

成员id、name[20]、score实际占用内存大小刚好是对齐值4的整数倍,而成员sex则需要开辟4字节空间,实际只占用1字节,剩余3字节未使用;成员addr[30]需要开辟32字节空间,实际使用30字节,剩余2字节未使用。因此打印结构体变量student1所占内存大小为64字节。

2、修改默认指定对齐值
在上述示例基础之上修改默认指定对齐值:

#include <stdio.h>
#pragma pack(1) //  指定默认对齐值为1
typedef struct
{
    char sex;       //  性别
    int id;         //  学号
    char name[20];  //  姓名
    float score;    //  成绩
    char addr[30];  //  地址
}STU;
#pragma pack()  //  取消修改对齐值
int main(){
    STU student1;
    printf("size of student1: %d\n",sizeof(student1));    //  打印结构体变量所占内存长度
    return 0;
}

此时程序输出结果为:

size of student1: 59

以上代码使用#pragma pack(1) 将默认指定对齐值修改为1,那么结构体成员将会按照1字节做内存对齐。

成员实际占用内存大小系统开辟内存空间大小
sex11
id44
name[20]2020
score44
addr[30]3030

此时打印结构体变量student1所占内存长度就为59。

如果将默认指定对齐值修改为2呢?

#include <stdio.h>
#pragma pack(2) //  指定默认对齐值为1
typedef struct
{
    char sex;       //  性别
    int id;         //  学号
    char name[20];  //  姓名
    float score;    //  成绩
    char addr[30];  //  地址
}STU;
#pragma pack()  //  取消修改对齐值
int main(){
    STU student1;
    printf("size of student1: %d\n",sizeof(student1));    //  打印结构体变量所占内存长度
    return 0;
}

程序输出结果:

size of student1: 60
成员实际占用内存大小系统开辟内存空间大小
sex12
id44
name[20]2020
score44
addr[30]3030

这个时候除了成员sex之外,其余成员的自身对齐数均是2的整数倍,因此成员sex需要根据对齐数2进行内存对齐,开辟2字节空间存储,但实际只使用1字节空间,最后打印结构体变量student1的所占内存长度为60。

更多推荐

内存泄漏,内存溢出,抽象类和接口,netstat、ping、ifconfig的区别

持续学习是我们必备的技能之一,保持与时俱进,保持行业的敏感度,关注行业发展趋势,了解新技术,加强自己的认知,积极的应对变化内存泄漏memoryleak是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出内存泄漏可以分为四类1、常发性内存泄漏,发生内存泄漏的代

微信小程序部分知识点总结

简单描述下微信小程序的目录结构微信小程序的目录结构如下:app.js。微信小程序的主逻辑文件,用于描述小程序的基本逻辑和程序入口。app.json。微信小程序的公共设置文件,用于描述小程序的全局配置项,如页面路径、窗口样式等。app.wxss。微信小程序的公共样式表文件,用于描述小程序的全局样式,如字体、颜色等。pag

Java基于基于微信小程序的快递柜管理系统

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W+、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌文章目录第一章:简介第二章、***\*开发环境:\******后端:****前端:****数据库:**第三章系统设计3.3系统功能设计3.3.1用户注册

APP开发者如何运用积分墙广告,提升APP应用下载和用户留存?

“积分墙”移动广告通过在应用内展示各种积分任务,鼓励用户完成任务以获得积分奖励,从而增加应用的曝光度和下载量。一、什么是积分墙?积分墙是一种第三方移动广告平台。开发者可以在这类平台上发布任务(如下载安装App、注册、填表等),用户完成相应任务就可以获得积分或现金奖励,达到指定额度可以提现。二、积分墙包含哪几部分?(1)

springBoot整合minio

<minio.version>8.3.4</minio.version><!--其它&&数据源加密--><org.bouncycastle.bcprov-jdk15on.version>1.70</org.bouncycastle.bcprov-jdk15on.version><dependencies><depend

《向量数据库指南》——文心大模型+Milvus向量数据库搭建AI原生应用

亲爱的科技探险家们和代码魔法师们:未来的钟声已经敲响,预示着一场极度炫酷的虚拟现实游戏即将展开。从初期简单的智能识别,到设计师级别的图纸设计,生成式AI技术(GenerativeAI)以其独特理念和创新模式重塑了传统内容生产效率和交互模式,在无数领域展现着非凡的才华。在这场人工智能游戏中,高性能、高稳定的各类大模型的不

恩智浦i.MX8MM核心板在智能售货机产品中的应用方案-迅为电子

迅为i.MX8MM核心板在自动售货机产品中可以实现多种应用,提高自动售货机的功能和性能。以下是i.MX8MM核心板在自动售货机产品中的应用方案:支付和交易处理:i.MX8MM核心板可以用作自动售货机的支付和交易处理器,支持各种支付方式,如信用卡、手机支付、硬币和纸币识别,以提供便捷的购物体验。库存管理:核心板可用于实时

文举论金:黄金原油全面走势分析策略指导。

市场没有绝对,涨跌没有定势,所以,对市场行情的涨跌平衡判断就是你的制胜法宝。欲望!有句意大利谚语:让金钱成为我们忠心耿耿的仆人,否则,它就会成为一个专横跋扈的主人。空头,多头都能赚钱,唯有贪心不能赚。是你掌控欲望还是欲望掌控你?古人云:不积硅步无以至千里,不积小流无以成江海。希望这句话成为我们之间的共勉。自知!人贵自知

R语言绘图-3-Circular-barplot图

0.参考:https://r-graph-gallery.com/web-circular-barplot-with-R-and-ggplot2.html1.说明:利用ggplot绘制环状的条形图(circularbarplot),并且每个条带按照数值大小进行排列。2绘图代码:注意:绘图代码中的字体为“TimesNew

什么是单页面应用(SPA)?它们的优点和缺点是什么?

聚沙成塔·每天进步一点点⭐专栏简介⭐什么是单页面应用(SPA)?⭐SPA的优缺点是什么?⭐SPA中如何处理搜索引擎优化(SEO)?⭐什么是前端路由(Front-endrouting)在SPA中的作用是什么?⭐SPA中如何处理浏览器历史记录和页面刷新?⭐SPA通常使用哪些前端框架或库来简化开发?⭐写在最后⭐专栏简介前端入

WebGL笔记: 2D和WebGL坐标系对比和不同的画图方式, 程序对象通信,顶点着色器,片元着色器

WebGL坐标系canvas2d画布和webgl画布使用的坐标系都是二维直角坐标系,但它们坐标原点、y轴的坐标方向,坐标基底都不一样canvas2d坐标系的原点在左上角,x轴朝右,y轴朝下1个单位的宽就是一个像素的宽,1个单位的高就是一个像素的高,都是按像素来走webgl坐标系的原点在画布中心,x轴朝右,y轴朝上1个单

热文推荐