结构体内存对齐与联合体

news2024/11/12 18:42:24

目录

前言

结构体大小的计算

修改默认对齐数


前言

当我们了解结构体的声明,结构体的自引用,结构体变量的定义和初始化,如何计算结构体的大小呢?结构体类型的数据是在内存中如何存放的呢?这也是本文需要讨论的问题;

结构体大小的计算

//结构体声明
struct n
{
	char c1;
	int i;
	char c2;
};

int main()
{
	struct n n1;
    //计算结构体的大小
	printf("%d\n", sizeof(n1));
	return 0;
}

char-字符类型-大小为1字节   int - 整型 - 大小为4字节,那么总大小是不是 1+4+1=6字节呢?

运行结果:

结果是12个字节,为什么?这就不得不涉及结构体内存对齐规则;

结构体内存对齐规则

1. 结构体第一个成员变量存放在与结构体变量偏移量为0的地址处

2. 其他成员变量要对齐到对齐数的整数倍的地址处;

    对齐数=编译器默认对齐数与成员变量大小的较小值;

  vs默认对齐数为8字节,linux环境没有默认对齐数,对齐数就是成员自身的大小

3. 结构体总大小为最大对齐数的整数倍

4. 对于嵌套结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

接下来的讨论,全是在vs编译环境下,即默认对齐数为8; 假设创建结构体变量n1从0x0000ff40处开辟内存空间,示意图如下

 根据结构体对齐第一条规则:结构体第一个成员变量存放在与结构体变量偏移量为0的地址处;

  结构体成员变量c1就应该存放于偏移量为0的地址处,且占1byte; 如上图c1的位置;

根据结构体对齐第二条规则:其他成员变量要对齐到对齐数的整数倍的地址处;

1. 先计算对齐数 int在内存中占4个字节,默认对齐数为8个字节,对齐数为自身大小和默认对 齐数两者较小值 那么对齐数=4;结构体第二个成员变量就要对齐到4的整数倍,即偏移量等于4的位置,且占4byte,如上图i的位置;

2. 计算对齐数  har在内存中占1个字节,默认对齐数为8个字节,对齐数为自身大小和默认对 齐数两者较小值 那么对齐数=1;结构体第二个成员变量就要对齐到1的整数倍,即偏移量等于8的位置,且占1byte,如上图c2的位置;

 根据结构体对齐第三条规则:结构体总大小为最大对齐数的整数倍

 第一个对齐数=4,第二个对齐数=1 最大对齐数=4;结构体总大小=4*j (j=1,2,....)

已经用掉9个字节,下一个4的整数倍即偏移量为11的位置,12个字节;如上图绿色方框所示;

综上,已经分析出结果为12字节,那分析步骤是否如同我们如上所述,需要进行进一步验证

offsetof() - 宏 头文件 #include<stddef.h>

返回值为unsigned int ,第一个参数为结构体变量类型,第二个参数为成员变量名;

计算结构体成员相对于起始位置的偏移量

 验证如下:

# include <stddef.h>
struct n
{
	char c1;
	int i;
	char c2;
};
int main()
{
	printf("%u\n", offsetof(struct n, c1));
	printf("%u\n", offsetof(struct n, i));
	printf("%u\n", offsetof(struct n, c2));
	return 0;
}

运行结果:

 验证结果如上图所示,与示意图完美匹配,可以得出分析步骤完全正确;

当我们计算嵌套结构体的大小,如下计算n的大小,结果又是如何?

struct s
{
	double d;// 对齐数1=8;
	char c;//对齐数2=1;
	int i;//对齐数3=4;
};
//嵌套结构体最大对齐数=8字节;
//struct s的总大小经计算为16个字节

struct n
{
	char c1;//对齐数4=1;
	struct s n1;
	double d;//对齐数5=8;
};
int main()
{
	printf("%d\n", sizeof(struct n));
	return 0;
}

根据结构体对齐的第四条规则:对于嵌套结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍;

不难得出结论,结果为32字节;

修改默认对齐数

使用 # pragma预处理指令来修改默认对齐数

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

运行结果:

联合体

联合体定义

C语言中,变量的定义是分配存储空间的过程。一般的,每个变量都具有其独有的储存空间,那么是否可以在同一块存储空间储存不同的数据类型呢?

联合体也叫共用体,C语言中联合体的关键字是union,这种类型定义的变量也包含一些列的成员变量,特征是这些成员共用同一块内存空间;

//定义联合类型的声明
union 联合名
{
   成员列表;
};

验证过程:验证联合体成员是否共用同一块内存

union un
{
	char c;
	int i;
};
int main()
{
	union un u;
	printf("%p\n", &u);
	printf("%p\n", &(u.c));
	printf("%p\n", &(u.i));
	return 0;
}

运行结果:

 联合体大小的计算

联合体成员是共用同一块内存空间,一个联合变量的大小至少是最大成员的大小(因为联合体至少得有能力保存最大的成员变量);

//计算联合体的大小
union un
{
	char c;
	int i;
};
int main()
{
	union un u;
	printf("%d\n", sizeof(u));
	return 0;
}

运行结果:

但是联合体的大小一定是最大的成员的大小吗?

union un
{
	char arr[5];
	int i;
};
int main()
{
	union un u;
	printf("%d\n", sizeof(u));
	return 0;
}

运行结果:

 结果是8个字节,成员变量最大为int类型,只占4个字节,所以联合体变量的大小不一定是最大成员的大小;

联合体大小的计算

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

共用体从0偏移量处开始共用同一块内存空间,c为字符数组,数组成员为char,char占1个字节,vs默认对齐数为8,所以对齐数1=1;i为整型数据,占4个字节,vs默认对齐数为8所以对齐数2=8;所以最大对齐数=4;此时内存使用5个字节,但是要对齐到最大对齐数的整数倍的位置,即相对于起始位置的第8个字节处,即偏移量为7的位置,所以占用内存的大小为8字节;

 

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

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

相关文章

CVPR 2023 | 图像超分,结合扩散模型/GAN/部署优化,low-level任务,视觉AIGC系列

1、Activating More Pixels in Image Super-Resolution Transformer 基于Transformer的方法在低级别视觉任务中&#xff0c;如图像超分辨率&#xff0c;表现出了令人印象深刻的性能。Transformer的潜力在现有网络中仍未得到充分发挥。为了激活更多的输入像素以实现更好的重建&a…

Ansible配置和模块

Ansible是一个基于Python开发的配置管理和应用部署工具&#xff0c;现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点&#xff0c;Pubbet和Saltstack能实现的功能&#xff0c;Ansible基本上都可以实现。 Ansible能批量配置、部署、管理上千台主机。比如以前需…

Python自动化测试基础必备知识点总结

一、自动化测试的概念 性能系统负载能力稳定性过载操作下的系统瓶颈自动化测试&#xff0c;使用程序代替人工&#xff0c;可以提高测试效率性&#xff0c;自动化测试能自动化使用代码模拟大量用户&#xff0c;让用户请求多页和多用户并发请求收集参数&#xff0c;并对系统负载…

使用UnityXR配置PICO开发环境

效果展示&#xff1a; 一、说明 本文环境搭建测试基于Unity2021.3.26版本进行的&#xff0c;插件版本为当前官方最新版本PICO_SDK_v2.1.5&#xff0c;根据官方的描述&#xff0c;PICO Unity Integration SDK v2.x.x 系列是长期维护版本&#xff0c;支持 PICO Neo3 和 PICO 4 全…

VFP提取源码中各项信息,快速转换语言,时间比钱值钱

您辛苦了很长时间&#xff0c;编写了一套很不错的管理软件&#xff0c;行业使用很不错&#xff0c;代码行10万&#xff0c;有一天一位外国客户找到您&#xff0c;说想购买使用您的软件&#xff0c;但显示语言需要是英语的&#xff0c;三五天内就要使用&#xff0c;你怎么办&a…

Windows 禁止 IE 自动跳转 Edge「整合方案」

前言 IE 已经合并进 Edge 浏览器&#xff0c;IE「正式入土」 RESPECT ​ 昨晚&#xff0c;公司系统更新&#xff08;Edge&#xff09;结束后&#xff0c;原本正常运行的 RPA 全部下线&#xff0c;原因如图&#xff1a; ​ 早上起来&#xff0c;又是充满希望的一天&#xff0c;于…

Autoware.universe中激光雷达感知部分简述,一看就懂,不懂请打我

文章目录 整体把握各部分阐述滤除多余的检测框 总结 整体把握 Autoware.universe中激光雷达感知部分的主要流程为&#xff1a; 将原始点云数据输入地面滤波器和深度学习检测算法&#xff0c;分别得到地面滤波后的点云points_no_ground和Object检测框(该检测框内包含中心点、位…

端午赠礼:软件测试万能面试脚本,一节课学会软件测试,欸嘿

​ 写在前面&#xff1a; 又到端午了&#xff0c;四舍五入接下来马上要过年了&#xff0c;新一波的跳槽旺季马上来临&#xff0c;不知道你是不是已经安于现状&#xff0c;还是蓄势待发呢&#xff1f;最近我和我的同事们一顿讨论&#xff0c;拟写了大家可能会遇到的面试情况&…

大数据基础平台实施及运维

一、大数据介绍 1、为什么使用大数据技术 数据量越来越大&#xff0c;数据分析的实时性越来越强&#xff0c;数据结果应用范围越来越广。&#xff08;从用户的访问量、量、访问时间、访问频率&#xff0c;市场可以得到很多信息&#xff09; 2、大数据的定义 数据收集、数据…

随机数发生器设计(五)

随机数发生器设计&#xff08;五&#xff09;- 重播种、输出、自测试 4 重播种函数5 输出函数6 自测试 4 重播种函数 重播种函数利用熵输入及额外输入更新种子&#xff0c;同时对内部状态进行更新。重播种操作函数如下&#xff1a; 函数定义&#xff1a;SM3_RNG_Reseed(workin…

【数据库原理与实践】记忆型章节作业汇总

填空题部分&#xff1a; Chp 8 安全性与完整性 part 1&#xff1a; 数据库的安全性是指保护数据库以防止不合法的使用所造成的&#xff08; 数据泄露、更改或破坏 &#xff09;。计算机系统有三类安全性问题&#xff0c;即&#xff08; 技术安全 &#xff09;、管理安全和…

【gitflow】 概念基本介绍

gitflow 简介 什么是gitflow&#xff1f; 我们大家都很会用git&#xff0c;但是我们很少去关心我们要怎么用branch和版本控制。 只知道master是第一个主分支&#xff0c;其他分支都是次要分支&#xff0c; 那你知道如下的问题如何回答吗&#xff1f; 如何保证主分支的稳定…

vue3+ts封装axios 配置BASE_URL拦截器 单个接口的拦截 全局拦截器

1. config.ts 书写BASE_URL &#xff08; service/request/config.ts&#xff09; BASE_URL书写的方式很多 1: 直接在axios.create里面写死 &#xff0c;在打包或者测试的时候手动进行修改BASE_URL 2:新建一个文件 在文件里面判断当前的环境 进行赋值BASE_URL 3:定义.env文件 …

线程间同步

线程间资源竞争 int count 0;void * add(void *arg){int val,i;for(i 0;i< 5000;i ){val count;printf("%p: %d\n",pthread_self(),val);count val 1;}return nullptr; }int main(){pthread_t tida,tidb;pthread_create(&tida,NULL,add,NULL);pthread_c…

python爬虫进行AES解密遇到的问题

1、TypeError: Object type <class ‘str’> cannot be passed to C code 报错如下&#xff1a; File "C:\Python311\Lib\site-packages\Crypto\Util\_raw_api.py", line 143, in c_uint8_ptrraise TypeError("Object type %s cannot be passed to C cod…

【改进算法】混合鲸鱼WOA和BAT算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

0101B站学习视频发留言找小伙伴-实用小工具系列

文章目录 1 起因2 找方法3 bilibili_api4 实现5 知识点结语 1 起因 经常在B站看学习视频&#xff0c;但是一个人学习&#xff0c;偶尔在想&#xff0c;我学的怎么样&#xff1f;有没有用&#xff1f;有没有谁可以一起交流下&#xff1f;好在现在有互联网&#xff0c;可以极大的…

WiFi各协议理论速度

一、总览 二、11b到11g提升点 802.11g工作在2.4G频段下&#xff0c;能够支持OFDM和CCK两种调制方式&#xff0c;提供16-QAM、64-QAM、BPSK和QPSK四种编码方式&#xff0c;我们通常说的54Mbps速率就是在2.4G频段下&#xff0c;通过OFDM调制&#xff0c;采用64-QAM编码的情况下实…

表达式和语句

表达式 可以被求值的代码&#xff0c;并将其计算出一个结果 语句 一段可以执行的代码&#xff0c;是一个行为&#xff0c;例如分支语句和循环语句 三大流程控制语句 以前写的代码&#xff0c;写几句就从上往下执行 &#xff0c;---顺序结构 有时候要根据条件 选择执行代码…

Spring源码之PostProcessor解析

系列文章目录 文章目录 系列文章目录前言一、PostProcessor是什么二、PostProcessor的作用三、Spring框架中有哪些PostProcessor呢BeanPostProcessorBeanFactoryPostProcessorInstantiationAwareBeanPostProcessorDestructionAwareBeanPostProcessorMergedBeanDefinitionPostPr…