struct 结构体的内存对齐

news2024/12/26 21:07:07

💙作者:阿润菜菜

📖专栏:一起学习C言


本文目录

在内存中观察 

结构体内存对齐的规则:

为什么存在内存对齐?

编程中我们该如何设计结构体?

修改默认对齐数

相关笔试题


在内存中观察 

首先我们来看一段代码:这里有两个结构体,只有成员顺序不一样

//1
struct S1
{
 char c1;
 int i;
 char c2;
};

//2
struct S2
{
 char c1;
 char c2;
 int i;
};

那么你们觉得S2大小是几个字节?S1又是多少?

作为C语言初学者一般是这样认为的:char 1字节 int 4字节 所以都是6字节

​但实际上结果不是这样的,为什么呢?下面我们就来看看结构体内存对齐的知识:

如图,假设0为结构体S1在内存中的首地址,顺序123...为相对于首地址的偏移量(宏 offsetof  用来计算结构体成员相对于起始位置的偏移量)

​通过offsetof可以计算出三个变量(c1,i,c2)各自对应的偏移量: 0 ,4 ,8

​我们发现,在内存中红色的空间并没有被使用,而是都被浪费掉了,同样观察结构体S2成员变量排列情况: 

通过以上,我们可以知道结构体成员变量在内存中并不是按照顺序排列的,而是按照一定的规则进行内存对齐排序的:

结构体内存对齐的规则:

  • 结构体的第一个成员直接对齐到相对于结构体变量起始位置为0的地址处
  •  从第二个成员开始,要对齐到某个【对齐数】的整数倍的偏移处
  • 对齐数:结构体成员自身大小和默认对齐数的较小值VS中默认的值为8,Linux环境默认不设对齐数)
  • 结构体的总大小,必须是最大对齐数的整数倍。每个结构体成员都有一个对齐数,其中最大的对齐数就是最大对齐数
  • 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

为什么存在内存对齐?

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

1. 平台原因 ( 移植原因 )
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因
数据结构 ( 尤其是栈 ) 应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

编程中我们该如何设计结构体?

那在我们设计结构体的时候,我们既要满足对齐,又要节省空间: 让占用空间小的成员尽量集中在一起。
如:
//不推荐
struct S1
{
 char c1;
 int i;
 char c2;
};
//推荐
struct S2
{
 char c1;
 char c2;
 int i;
};

虽然S1S2类型的成员一模一样,但是S2所占的内存空间就少了一些

修改默认对齐数

在结构在对齐方式不合适的时候,我们可以利用#pragma 这个预处理指令更改默认对齐数:

#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
 char c1;
 int i;
 char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
 char c1;
 int i;
 char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

相关笔试题

1. 如下C程序,在64位处理器上运行后 sz 的值是什么( )

 正确答案:B
要注意的是64位的情况下指针是占8个字节的,剩余详细了解结构体内存对齐的规则

 2.百度笔试题: 写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明

#define  STRUCT_OFFSET(id, element)  ((unsigned long)(&(( struct id*)0)->element))
考察: offsetof 宏的实现
因为是求偏移量 所以假设结构体的首地址是0开始,把他转换成结构体指针类型,在用 -> 取得他的成员,前面加了一个& 就是取得这个成员的 地址,最后在强制转换成unsigned long, 这样就得到了偏移量。

本节完 

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

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

相关文章

el-date-picker 目前只能通过点击input输入框触发日期选择器,怎么通过其他方式触发日期选择器同时把input输入框去掉,如点击按钮

依然是该模块由于后端接口数据传输限制 在前面文章里做了些许改动。 需求左右切换 可以快速找到年份&#xff0c;于是添加了element选择年份的日期组件。 图中隐藏了el-data-picker日期组件&#xff0c;手动添加样式展示时间栏选择的数据进行 0 回显。 点击时间时&#xff0c;…

想看看一个影片评论怎么样?python带你采集数据做词云

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 目录前言环境使用:模块使用安装python第三方模块:思路分析代码展示数据采集词云图尾语 &#x1f49d;环境使用: Python 3.8 解释器 Pycharm 编辑器 模块使用 import parsel >>> pip install parsel import req…

《玩转 Spring 全家桶》学习笔记Day1

Spring 诞生于2002年&#xff0c;成型于2003年。Spring Boot 负责构建、Spring Cloud 协调、Spring Cloud Data Flow 负责连接一切。Spring Framework理念&#xff0c;向后兼容&#xff0c;专注API设计&#xff0c;让选择无处不在&#xff0c;海纳百川&#xff0c;严苛的代码质…

N+1终于等到了 但却放弃了

在公司呆了8年了&#xff0c;做梦都想被开除&#xff0c;年底等到了。但......2021年年底绩效B&#xff0c;可是公司年终奖泡沫了&#xff1b;估摸着2022年公司可能会发奖金&#xff0c;那我也悄悄的给自己定了目标&#xff0c;大干一场&#xff0c;争取过年拿个好结果。跟着公…

Go语言的数据类型

博客主页&#xff1a;&#x1f3c6;看看是李XX还是李歘歘 &#x1f3c6; &#x1f33a;每天不定期分享一些包括但不限于计算机基础、算法、后端开发相关的知识点&#xff0c;以及职场小菜鸡的生活。&#x1f33a; &#x1f497;点关注不迷路&#xff0c;总有一些&#x1f4d6;知…

功率放大器模块在超微晶合金磁特性测量研究中的应用

客户需求&#xff1a;对超微晶合金磁特性测量中的波形发生与控制问题进行研究&#xff0c;实验系统有严格的体积要求&#xff0c;上位机可外置&#xff0c;测试系统需集成于机箱&#xff0c;机箱尺寸&#xff1a;1900mm500mm600mm。 解决方案&#xff1a;功率放大器模块采用安泰…

Golang的error和panic

博客主页&#xff1a;&#x1f3c6;看看是李XX还是李歘歘 &#x1f3c6; &#x1f33a;每天不定期分享一些包括但不限于计算机基础、算法、后端开发相关的知识点&#xff0c;以及职场小菜鸡的生活。&#x1f33a; &#x1f497;点关注不迷路&#xff0c;总有一些&#x1f4d6;知…

Python入门自学进阶-Web框架——30、DjangoAdmin项目应用-自定义用户认证续

一、前面实现的是DjangoAdmin实现的自定义用户认证管理&#xff0c;现在自己来实现管理功能&#xff0c;即在mytestapp中增加用户认证管理功能。 在UserProfile的model中&#xff0c;对password字段增加help_text属性&#xff1a; password models.CharField(_(password), m…

Linux 环境安装 jdk 或 openjdk

一、linux 环境安装JDK的tar.gz包&#xff0c;通用命令&#xff1a; 1、查看已安装的JDK版本rpm -qa | grep jdk2、删除不需要的JDK版本&#xff1a;rpm -e --nodeps java-1.8.0-openjdk3、解压新JDK至/usr/lib/jvm目录下tar -zxvf openjdk-1044_linux-x64_bin_ri.tar.gz -C /…

AOSP刷机笔记

下载官方镜像&#xff0c;下载对应AOSP&#xff0c;编译出的*.img替换到官方镜像对应的文件, 刷入 把证书放到aosp源码的system/ca-certificates/files文件夹里&#xff0c;lunch aosp_sailfish-user编译可以实现无root抓包 mkdir ~/bin PATH~/bin:$PATH curl -sSL https://ger…

什么是集中采购 集中采购管理软件介绍

什么是集中采购&#xff1f; 集中采购是指企业总部某特定部门对企业所有采购进行管控&#xff0c;他们负责获取整个组织需要的物资。这个部门负责与供应商联络、供应商寻源、合同管理、风险分析&#xff0c;以及从供应商那里获得所需物资的每项工作。 企业采用集中采购管理模…

什么叫joinquant量化策略?

joinquant量化主要是在数据挖掘上有特别的意义&#xff0c;不像平时我们在执行各个量化选股策略时&#xff0c;还要一个一个去输入去查询。而joinquant量化策略在开发方面就简便了很多&#xff0c;joinquant量化策略是运用到个股量化交易中能够针对各个股票数据都能快速挖掘出来…

mongodb安装和部署,并整合到Springboot

mongodb安装和部署,并整合到Springboot 1.linux上docker安装mongodb docker pull mongo:4.4.18使用docker命令启动&#xff1a; docker run -p 27017:27017 --name mongo \ -v /mydata/mongo/db:/data/db \ -d mongo:4.4.18运行容器 docker exec -it mongo /bin/bash# 进入…

C进阶_字符串查找库函数

strstr 查找strstr的文档&#xff0c;可知它的原型为&#xff1a; char *strstr( const char *string, const char *strCharSet ); 它的返回值&#xff0c;根据文档是这样的&#xff1a; Return Value Each of these functions returns a pointer to the first occurrence …

使用 YonBuilder 进行报表分析 - 扩展篇

使用 YonBuilder 进行报表分析 - 扩展篇 在上一篇文章中&#xff0c;我们讲解了如何构建简单的报表以及交叉表的基础配置。本篇文章通过对主子表、树型表以及数据穿透的创建来对 YonBuilder 的报表配置进行扩展介绍。 创建报表 首先&#xff0c;要先创建一个员工信息实体&…

CSS选择器整理学习(中)

书接上回&#xff0c;在前端项目开发中&#xff0c;有时候需要对特殊的元素进行特殊的处理&#xff0c;但有时候元素的位置不确定、层级不确定、数量不确定等问题&#xff0c;导致我们没办法进行元素的选择&#xff0c;这个时候我们就需要用到元素选择器了。 一、CSS选择器 1…

加油站视频监控智能分析盒基于yolov5

加油站视频监控智能分析盒基于yolov5人工智能视觉技术&#xff0c;对现场画面中明火和烟雾以及人员抽烟、打电话等违规行为进行识别。除此之外&#xff0c;还可以对现场画面中卸油时灭火器未按要求正确摆放以及静电释放时间不足和人员离岗等不规范行为进行自动预警。YOLOv5在YO…

【云原生】k8s图形化管理攻击之rancher

内容预知 前言 1. Rancher的相关知识 1.1 Rancher的简介 1.2 Rancher与k8s的关系及区别 1.3 Rancher具有的优势 2. Rancher的安装部署 2.1 实验环境与部署图分配 2.2 具体的部署操作 &#xff08;1&#xff09;在 rancher 节点下载 rancher 镜像 &#xff08;2&#xff…

程序员同事每天准点下班,原来是用了这6个开发工具

工欲善其事必先利其器&#xff0c;要想更加高效的做事情&#xff0c;就得先将工具变得锋利。那么对于程序员来说同样也是如此&#xff0c;如果要想每天早点下班&#xff0c;就必须借助于一些开发工具来提高自己的工作效率&#xff0c;今天就给大家总结一些工作中常用到的工具。…

【算法题解】11. 判断链表是否有环,并返回入环节点

文章目录题目解法一&#xff1a;循环标记Java代码实现Go 代码实现复杂度分析解法二&#xff1a;快慢指针Java 代码实现Go 代码实现复杂度分析这是一道 中等难度 的题&#xff0c;是 判断链表是否有环 的扩展&#xff0c;在有环的情况下返回入环节点&#xff0c; 依然是两种解法…