C进阶_结构体内存对齐

news2024/11/26 19:30:36

请看下面的代码,输出结果是多少?

#include <stdio.h>
int main()
{
	struct S1
	{
		char c1;
		int i;
		char c2;
	};
	printf("%d\n", sizeof(struct S1));
	struct S2
	{
		char c1;
		char c2;
		int i;
	};
	printf("%d\n", sizeof(struct S2));
	return 0;
}

经调试可得到以下结果:

众所周知,在x86环境下,char型是1个字节,int型是4个字节。不论是在结构体S1还是结构体S2中都是两个char型和一个int型,那为什么输出结果不是两个6呢?这就涉及到结构体内存对齐的问题了。

结构体的对齐规则如下:

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

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。VS中默认的值为8。

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

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

以结构体S1为例,用图演示结构体内存对齐方式:

这印证了结构体内存对齐的第一个规则,即

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

我们继续:

在VS中默认对齐数是8,而int型大小是4,那么就取较小的数4作为对齐数。 4就是4的整数倍,所以就在4处对齐。

要注意在不同编译器下默认对齐数不一样,如在Linux gcc下就没有默认对齐数,对齐数就是结构体成员自身大小。

继续:

 char型大小是1个字节,VS中默认对齐数是8,那么就取较小的值1作为对齐数。8是1的整数倍,所以就在8处对齐。

现在,从0到8总共占了9个字节,那么结构体大小就是9吗?显然不是,因为之前提到过:

结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

现在已知c1的对齐数是1,i的对齐数是4,c2的对齐数是1,那么在这个结构体中,最大的对齐数就是4。

那么结构体大小就如下:

结构体大小是12。 

最后用宏offsetof来证明下,引用stddef.h头文件,然后执行以下代码,可得出每个成员的偏移量:

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

如果结构体发生了嵌套怎么办?

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

什么意思?

举例来看:

在S3中,double大小是8,char大小是1,int大小是4。

8+1+4=13。S3的最大对齐数是8,那么S3的大小就是最大对齐数的整数倍16。

在S4中c1对齐数为1,大小为1。

s3的对齐数已知是8,大小为16。

图中黑色方块代表s3。

在S4中d的对齐数为8,那么在s3后,24便是8的整数倍数,double的大小是8。

因为c1对齐数是1,s3对齐数是8,d的对齐数是8,那么S4中最大对齐数是8,32又是8的整数倍数,所以S4的大小就是32。

再来看s3的成员是如何对齐的:

至于为什么要有结构体内存对齐?目前暂时没有官方的理由。但是有以下说法:

1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

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

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

那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到?

#include <stdio.h>
int main()
{
	struct S1
	{
		char c1;
		int i;
		char c2;
	};
	struct S2
	{
		char c1;
		char c2;
		int i;
	};
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));
	return 0;
}

通过对比输出结果可发现S2占用空间更小:

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

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

相关文章

Xmake v2.7.6 发布,新增 Verilog 和 C++ Modules 分发支持

Xmake 是一个基于 Lua 的轻量级跨平台构建工具。 它非常的轻量&#xff0c;没有任何依赖&#xff0c;因为它内置了 Lua 运行时。 它使用 xmake.lua 维护项目构建&#xff0c;相比 makefile/CMakeLists.txt&#xff0c;配置语法更加简洁直观&#xff0c;对新手非常友好&#x…

前端CSS学习之路-css002

&#x1f60a;博主页面&#xff1a;鱿年年 &#x1f449;博主推荐专栏&#xff1a;《WEB前端》&#x1f448; ​&#x1f493;博主格言&#xff1a;追风赶月莫停留&#xff0c;平芜尽处是春山❤️ 目录 CSS字体属性 一、字体系列 二、字体大小 三、字体粗细 四、文字样…

Docker安装nacos

首先将自己的服务器在配置上弄成docker的 然后再下方命令框中直接粘贴如下命令&#xff1a; docker run –name nacos -d -p 8848:8848 -p 9848:9848 -p 9849:9849 –restartalways -e JVM_XMS256m -e JVM_XMX256m -e MODEstandalone -v /usr/local/nacos/logs:/home…

基于多协议传感器的桥梁监测数据采集与管理系统设计

文章目录前言1、要求&#xff1a;2、系统框图2.1系统总体框图2.2、stm32通过AHT20采集温湿度框图&#xff1a;2.3、stm32通过modbus协议与上位机通信框图&#xff1a;3、ModBus协议1、协议概述2、Modbus主/从协议原理3、通用Modbus帧结构---协议数据单元(PDU)4、两种Modbus串行…

readonly与disabled对比

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>readonly与disabled</title> </head> <body> <!--readonly与disabled 都是只读不能修改…

传统推荐模型(二)协同过滤的进化——矩阵分解算法

传统推荐模型&#xff08;二&#xff09;协同过滤的进化——矩阵分解算法 针对协同过滤算法的头部效应较明显、泛化能力较弱的问题&#xff0c;矩阵分解算法被提出。矩阵分解在协同过滤算法中“共现矩阵”的基础上&#xff0c;加人了隐向量的概念&#xff0c;加强了模型处理稀…

动态顺序表——简单的增删查改

前言 &#xff1a;从这篇博客开始&#xff0c;我会进行数据结构(用C语言实现)有关内容的记录与分享。对于我们而言&#xff0c;数据结构的知识难度较大并且十分重要&#xff0c;希望我的分享给各位带来一些帮助。而今天要分享的就是数据结构中最简单的知识——顺序表的增删查改…

11.Java方法的综合练习题大全-双色球彩票系统,数字的加密和解密等试题

本篇文章是Java方法的专题练习,从第五题开始难度增大,涉及大厂真题,前四道题目是基础练习,友友们可有目的性的选择学习&#x1f618;&#x1f495; 文章目录前言一、数组的遍历1.注意点:输出语句的用法2.题目正解二、数组最大值三、判断是否存在四、复制数组五、案例一:卖飞机票…

【学习笔记之数据结构】二叉树(一)

二叉树的概念&#xff1a; 二叉树是一种树的度不大于2的树&#xff0c;也就是它的节点的度都是小于等于2的。二叉树的子树有左右之分&#xff0c;左右的次序不能颠倒&#xff0c;因此二叉树是一个有序树。任意的二叉树都由空树、只有根节点、只有左子树、只有右子树、左右子树均…

一个简单的自托管图片库HomeGallery

什么是 HomeGallery &#xff1f; HomeGallery 是一个自托管的开源 Web 图片库&#xff0c;用于浏览个人照片和视频&#xff0c;其中包括标记、对移动端友好和 AI 驱动的图像和面部发现功能。 HomeGallery 的独特功能是自动 相似图像/反向图像搜索功能 和 无数据库架构 &#x…

实验三、8人智力竞赛抢答电路设计

实验三 8人智力竞赛抢答电路设计 实验目的 设计一个能支持八路抢答的智力竞赛抢答器&#xff1b;主持人按下开始抢答的按键后&#xff0c;有短暂的报警声提示抢答人员抢答开始且指示灯亮表示抢答进行中&#xff1b;在开始抢答后数码管显8秒倒计时&#xff1b;有抢答人员按下抢…

Linux企业应用现状

一、Linux在服务器领域的发展 随着开源软件在世界范围内影响力日益增强&#xff0c;Linux服务器操作系统在整个服务器操作系统市场格局中占据了越来越多的市场份额&#xff0c;已经形成了大规模市场应用的局面。并且保持着快速的增长率。尤其在政府、金融、农业、交通、电信等国…

linux 网络编程socket

前言 socket&#xff08;套接字&#xff09;是linux下进程间通信的一种方式&#xff0c;通常使用C-S&#xff08;客户端-服务端&#xff09;的方式通信&#xff0c;它可以是同一主机下的不同进程间通信或者不同主机的进程通信。 socket是夹在应用层和TCP/UDP协议层间的软件抽象…

机器自动翻译古文拼音 - 将进酒拼音版本,译文拼音版本

写了一个程序&#xff0c;用来给佛经和古诗加上拼音&#xff0c;并处理多音字和排版&#xff0c;顺便加上翻译。 定期翻译一些&#xff0c;给老人和小孩子用。 将进酒 君不见&#xff0c;黄河之水天上来&#xff0c;奔流到海不复回。 君不见&#xff0c;高堂明镜悲白发&…

Servlet介绍及其概念

Servlet介绍及其概念一、Web基础二、编写HTTP Server&#xff0c;打印Hello,World三、Servlet的出现1. 思考上述HTTP服务器的问题2. 实现代码重用&#xff0c;简化开发过程3. 实现最简单的Servlet4. 导入依赖5. pom.xml文件6. Servlet版本问题7. 整个Servlet工程结构四、运行Se…

Windows卸载与清除工具 “ Geek 与 CCleaner ”

前言 &#x1f4dc;“作者 久绊A” 专注记录自己所整理的Java、web、sql等&#xff0c;IT技术干货、学习经验、面试资料、刷题记录&#xff0c;以及遇到的问题和解决方案&#xff0c;记录自己成长的点滴 目录 前言 一、Geek的简介 1、大概介绍 2、详细介绍 二、Geek的下载 1、…

千峰Ajax【fetch和promise】

promise基础 <script>// Promise构造函数var q new Promise(function (resolve, reject) {//异步setTimeout(function () {// 成功// resolve(["111", "222", "333"]);// 失败reject("error");}, 2000);});// q是promise对象q…

利用系统函数与堆栈快速定位app关键代码

string.trim 这个还是比较关键的&#xff0c;没准可以从这里得到加密方式&#xff0c;或者挖到sql注入&#xff0c;文件上传等漏洞。进一步利用可以打印堆栈来用 Java.perform(function(){function showStack(){console.log(Java.use("android.util.Log").getStack…

TCP/IP网络编程——基于 TCP 的服务端/客户端(下)

完整版文章请参考&#xff1a; TCP/IP网络编程完整版文章 文章目录第 5 章 基于 TCP 的服务端/客户端&#xff08;2&#xff09;5.1 回声客户端的完美实现5.1.1 回声服务器没有问题&#xff0c;只有回声客户端有问题&#xff1f;5.1.2 回声客户端问题的解决办法5.1.3 如果问题不…

chrome插件开发时使用import

问题描述 在进行chrome插件开发时&#xff0c;我们有时会希望把一些公共的方法包装成一个模块&#xff0c;例如发送网络请求的方法&#xff0c;然后在其他js文件中import然后调用&#xff0c;但是在实际操作时&#xff0c;遇到了这样的问题&#xff1a; 控制台报错cannot use …