当前位置: 首页 > news >正文

C语言----字节对齐

一:字节对齐的概念

        针对字节对齐,百度百科的解释如下:

        字节对齐是字节按照一定规则在空间上排列,字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位,一个字节等于8位二进制数,在UTF-8编码中,一个英文字符等于一个字节,字节按照一定规则在空间上排列就是字节对齐。

        上面就提到按照一定规则,那规则是什么,按什么规则去对齐,带着这个疑问往下走

二:为什么要字节对齐

        我们为什么要进行字节对齐,不对齐会有什么后果,在计算机中我们任何一个动作无非就是保证程序的正确性,提高程序的性能和可靠性。

        1,平台的硬要求,必须要字节对齐

        某些平台对特定类型的数据只能从特定地址开始存取,而不允许其在内存中任意存放。例如,Motorola 68000 处理器不允许16位的字存放在奇地址,否则会触发异常,因此在这种架构下编程必须保证字节对齐。

        2,提高程序的性能

        字节对齐如何能提高程序的性能?CPU内部有几个重要的部件决定了CPU一次能处理的字节和可访问的内存大小。寄存器,ALU和数据总线的位数,这些共同决定了CPU的字长,常见CPU的字长有4位,8位,16位,32位和64位。字长越多,则CPU内部硬件规模和造价越高。如果CPU字长是16位。它的寄存器和总线也是16位。那么它一次处理的数据长度就为2字节。

        当访问一个变量时,当该变量的地址为偶地址(即字变量的低字节在偶地址单元,高字节在奇地址单元),则需要一个总线周期访问该字变量;如果该字变量的地址为奇地址(即字变量的低字节在奇地址单元,高字节在偶地址单元),则需要用两个连续的总线周期才能访问该字变量,每个周期访问一个字节。

        字节对齐让CPU读取数据的效果高了,这就解释了为什么字节对齐能提高程序的性能。

        3,节省程序的内存

        下面我们以一个实际的例子来看看字节对齐如何节省内存

#include <stdio.h>
#include <stdlib.h>struct byte1
{char a;int b;short c;
};struct byte2
{char a;short c;int b;
};int main()
{// please write your code hereprintf("struct byte1 size:%d\n",sizeof(struct byte1));printf("struct byte2 size:%d\n",sizeof(struct byte2));
}

 可以看到,同样是存储一个char,一个int,一个short,结构体中顺序不一样,结构体的所占的空间也不一样。之所以出现上述结果,就是因为编译器要对数据成员在空间上进行对齐

三:字节对齐规则

1,基本类型对齐规则

基本类型包括char、int、float、double、short、long等基本数据类型。CPU位数不同所占的字节数也不一样,如下图所示

在这里插入图片描述

         对齐要求:起始地址为其长度的整数倍即可。如,int类型的变量起始地址要求为4的整数倍,char类型的变量只占一个字节,那起始地址放哪都行。

2,结构体对齐规则

1>每个数据成员的起始位置必须是自身大小的整数倍; 

2>结构体总大小必须是结构体成员中最大的对齐模数的整数倍;

3> 结构体包含数组时,按单个类型对齐方式;

4>共用体union取成员的最大内存,但包含在结构体内时,按union内部最大类型字节数的整数倍开始存储;

struct byte1
{char a;int b;short c;
};

结构体大小:12
解释:char占一个字节,int占四个字节,由于int的起始地址要在4的倍数上,char后边补齐3个字节,shor占两个字节,但是整个结构体大小要是最大的对齐模数的整数倍,即4的倍数,所以补两个字节,一共12个字节

struct byte2
{char a;short c;int b;
};

结构体大小:8

解释:char占一个字节,short占两个字节,由于short的起始地址要在2的倍数上,char后边补齐1个字节,int占四个字节,刚好在4的倍数上,所以总共8个字节

那结构体里嵌套结构体呢?

结构体包含另一个结构体成员,则被包含的结构体成员要从其原始结构体内部的最大对齐模数的整数倍地址开始存储(比如struct a里含有struct b,b中有char、double 、int 元素,那么b应该从8(double)的整数倍开始存储)

结构体嵌套共同体

结构体包含共用体成员,则该共用体成员要从其原始共用体内部成员中的最大对齐模数的整数倍地址开始存储

结构体最后包含0数组

struct byte2
{char a;short c;int b;double d[0];
};

结构体最后包含0数组,那0数组占空间吗?长度为0的数组的主要用途是为了满足需要可变长度的结构体,具体用法是在一个结构体的最后,申明一个长度为0的数组,就可以使得这个结构体是可变长的。对于编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量,数组名这个符号本身代表了一个不可修改的地址常量。

3,共同体对齐规则

共同体的内存除了取最大成员内存外,还要保证是所有成员类型size的最小公倍数。

union byte3
{char a;short c[5];int b;
};

 共同体byte3中最大成员就是short c[5],占10个字节,由于要保证是所有成员类型size的最小公倍数,即4个倍数,所以是12

4,存在#pragma pack宏的对齐规则

#pragma pack(n)//编译器将按照n个字节对齐

#pragma pack()//取消自定义字节对齐方式

******对齐规则******

结构体、联合、类的结构成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和自身对齐模数中最小的那个。

结构体的大小是#pragma pack指定的数值的整数倍。

#pragma pack(4)
typedef struct 
{int age;char name[0];double a;
} Person;
#pragma pack();//结束#pragma pack(4)对齐。  如果没有结束,aa也按照#pragma pack(4)对齐typedef struct 
{double age;Person k;
} aa;int m=sizeof(Person); // m=12, 按照4字节对齐
int n=sizeof(aa); // n=24,  按照8字节对齐        按照#pragma pack(4)对齐的话,n=20

5,位域字节对齐规则

“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。使用位域的主要目的是压缩存储。

位域列表的形式为: 类型说明符 位域名:位域长度(单位:位 bite)

如:struct bs
      {
           int a:8;
           int b:2;
           int c:6;
       } data;
其中位域a占8位,位域b占2位,位域c占6位。

位域说明:

1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域

2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节(8位)的长度,也就是说不能超过8位二进位。
3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如: int :2
 

位域对齐规则

1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

3) 如果相邻的位域字段的类型不同从新的存储单元开始,偏移量为其类型大小的整数倍,即不压缩;(各编译器的具体实现有差异,VC6采取不压缩方式,Dev-  

     C++采取压缩方式)

4) 如果位域字段之间穿插着非位域字段,则不进行压缩

5) 整个结构体的总大小为最宽基本类型成员大小的整数倍


例题:

(1)typedef struct  AA
{
       unsigned int b1:5;
       unsigned int b2:5;
       unsigned int b3:5;
       unsigned int b4:5;
       unsigned int b5:5;
}AA;

sizeof(AA)= 4 

【解析】参考规则 1)。由于相邻成员类型相同,unsigned int为 4 个字节,b1占5位,b2加上b1的位数之和为10位,不超过4字节,因此b2接着b1继续存储;

      同理b3、b4、b5的类型相同,位数之和不超过4字节,因此接着b2继续存储,总位数为25位。

      由于结构体的大小是最宽类型成员的整数倍,因此25位之后的补0,直到补满4字节。

(2)typedef struct  AA
{
       unsigned int b1:5;
       unsigned int b2:5;
       unsigned int b3:5;
       unsigned int b4:5;
       unsigned int b5:5;
       unsigned int b6:5;
       unsigned int b7:5;
}AA;
   sizeof(AA)= 8 

【解析】参考规则 1) 和规则 2) 。由于相邻成员类型相同,unsigned int为 4 个字节(32位),当存储到 b7 时,b7和b6之前的位数相加超过4字节,

因此b7从新的存储单元开始存储。

即b1~b6 存储在 第0~29位,第30、31位补0,b7从下一个 4字节存储单元 开始存储5位,剩下的补0。

 (3)struct test1

{

char a:1;

char :2;

long b:3;

char c:2;

};

 sizeof(test1)= 12

【解析】 

char a:1; //用一个字节去存储

char :2;  //空域。因为与前面的a的类型相同,而两个位域的位宽相加仍然少于8位,所以依然用1个字节表示

long b:3; //long类型的位宽是4个字节,与前面的char类型不同,所以b与a之间偏移4个字节,它们之间自动补充3个字节 

char c:2; //因为c与b又不同型,以test1中的最长的long类型的位宽进行偏移,所以虽然char只用1个字节就够了,但依然要占4个字节。

结构体总长以最长的类型位宽做为偏移量,最长的是long型,占4位,所以不同类型之间应该是4个字节的偏移,即test1应该是4字节的整数倍。 

总共是12字节。

相关文章:

C语言----字节对齐

一&#xff1a;字节对齐的概念 针对字节对齐&#xff0c;百度百科的解释如下&#xff1a; 字节对齐是字节按照一定规则在空间上排列&#xff0c;字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位&#xff0c;一个字节等于8位二进制数&#xff0c;在UTF-8编…...

Next.js入门介绍(服务端渲染)

Next.js 一 目录 不折腾的前端&#xff0c;和咸鱼有什么区别 目录一 目录二 前言三 设置四 多页面五 链接六 样式七 共享组件八 布局组件九 实战 9.1 目录结构 9.2 UI 组件 9.3 Markdown 内容 9.4 Pages 入口和 API  9.4.1 服务端渲染 9.5 Public 静态资源 9.6 resor…...

模板Plus

文章目录 1.非类型模板参数的引入2.标准库和普通数组3.模板的特化 1.非类型模板参数的引入 //非类型模板参数 -- 常量 template<class T, size_t N 10> class array { private:T _a[N]; };int main() {array<int> a1;array<int, 100> a2;array<double, …...

spring事务和数据库事务是怎么实现

Spring事务的原理 Spring事务的本质其实就是数据库对事务的支持&#xff0c;没有数据库的事务支持&#xff0c;spring是无法提供事务功能的。对于纯JDBC操作数据库&#xff0c;想要用到事务&#xff0c;可以按照以下步骤进行&#xff1a; 获取连接 Connection con DriverManag…...

el-date-picker设置默认当前日期

HTMl部分&#xff1a; <el-form-item label"拍摄时间&#xff1a;"><el-date-pickerv-model"searchData.filmingTimeRange"type"daterange"align"right"unlink-panelsrange-separator"至"start-placeholder"…...

vue中使用this.$refs获取不到子组件的方法,属性方法都为undefined的解决方法

问题描述 vue2中refs获取不到子组件中的方法&#xff1f;&#xff0c;而获取到的是undefined 原因及解决方案&#xff1a; 第一种、在循环中注册了很多个ref 因为注册了多个ref&#xff0c;获取是不能单单知识refs.xxx&#xff0c;需要使用数组和索引来获取具体一个组件refs[…...

Linux命令200例:df用于显示文件系统的磁盘空间使用情况

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…...

Service not registered 异常导致手机重启分析

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 一、Service not registered 异常导致手机重启二、Service not registered 解决方案 一、Service not registered 异常导致手机重启 1.重启 的部分Log如…...

深度解读|一站式ABI平台 Smartbi Insight V11 能力再升级

纵观过去&#xff0c;我们发现汽车和BI的发展有异曲同工之妙。 100来年&#xff0c;汽车的动力从蒸汽到燃油再到新能源&#xff0c;汽车的操控方式从手动到自动再到智能无人驾驶。而在BI领域&#xff0c;自1958年BI的概念提出后&#xff0c;底层数据准备从报表开发、Cube多维模…...

vConsole手机调试模式uniapp和原生h5

手机打开调试模式的方法 尽量放在页面头部&#xff0c;底部有可能不行 原生 <script src"https://cdn.bootcss.com/vConsole/3.3.0/vconsole.min.js"></script> <script>// init vConsolevar vConsole new VConsole();console.log(Hello world)…...

Flutter Dart语言(05)异步

0 说明 该系列教程主要是为有一定语言基础 C/C的程序员&#xff0c;快速学习一门新语言所采用的方法&#xff0c;属于在C/C基础上扩展新语言的模式。 1 async和await 在Dart语言中&#xff0c;虽然没有像其他语言&#xff08;如Java、C、Python&#xff09;中的传统多线程概…...

滇医通微信小程序分析笔记

注意 本文章仅供学习交流使用&#xff0c;如果你是铁粉你就会知道博主之前发布过一篇相关的文章&#xff0c;但是由于代码涉及到法律相关所以就隐藏了&#xff0c;两年的时间过去了&#xff0c;因为女朋友已经早早安排上了&#xff0c;所以就搁置了&#xff0c;本次不做代码分…...

IoTDB在springboot2中的(二) 查询

上一章我们处理的基本的构建接入&#xff0c;以及插入的处理&#xff0c;那么接下来我们进行查询的操作处理。 我们继续在IoTDBSessionConfig工具类中加入查询的方法处理 /*** description: 根据SQL查询最新一条数据* author:zgy* param sql sql查询语句&#xff0c;count查询…...

SpringBoot 底层机制分析【Tomcat 启动+Spring 容器初始化+Tomcat 如何关联Spring 容器】【下】

&#x1f600;前言 本篇博文是关于SpringBoot 底层机制分析实现&#xff0c;希望能够帮助你更好的了解SpringBoot &#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大…...

NLP(六十五)LangChain中的重连(retry)机制

关于LangChain入门&#xff0c;读者可参考文章NLP&#xff08;五十六&#xff09;LangChain入门 。   本文将会介绍LangChain中的重连机制&#xff0c;并尝试给出定制化重连方案。   本文以LangChain中的对话功能&#xff08;ChatOpenAI&#xff09;为例。 LangChain中的重…...

C字符串与C++ string 类:用法万字详解(上)

目录 引言 一、C语言字符串 1.1 创建 C 字符串 1.2 字符串长度 1.3 字符串拼接 1.4 比较字符串 1.5 复制字符串 二、C字符串string类 2.1 解释 2.2 string构造函数 2.2.1 string() 默认构造函数 2.2.2 string(const char* s) 从 C 风格字符串构造 2.2.3 string(co…...

async/await函数需要trycatch吗?

前言 写异步函数的时候&#xff0c;promise 和 async 两种方案都非常常见&#xff0c;甚至同一个项目里&#xff0c;不同的开发人员都使用不同的习惯, 不过关于两者的比较不是本文关注的重点&#xff0c;只总结为一句话&#xff1a;“async 是异步编程的终极解决方案”。 当使…...

Jenkins集成appium自动化测试(Windows篇)

一&#xff0c;引入问题 自动化测试脚本绝大部分用于回归测试&#xff0c;这就需要制定执行策略&#xff0c;如每天、代码更新后、项目上线前定时执行&#xff0c;才能达到最好的效果&#xff0c;这时就需要进行Jenkins集成。 不像web UI自动化测试可以使用无痕浏览器做到无界…...

MongoDB:切换log日志文件

可以不重启MongoDB&#xff0c;切换日志文件 use admin db.runCommand({logRotate:1})参考 MongoDB 日志切割三种方式...

代码随想录第三十五天

代码随想录第三十五天 Leetcode 860. 柠檬水找零Leetcode 406. 根据身高重建队列Leetcode 452. 用最少数量的箭引爆气球 Leetcode 860. 柠檬水找零 题目链接: 柠檬水找零 自己的思路:我的垃圾思路&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;复…...

块、行内块水平垂直居中

1.定位实现水平垂直居中 <div class"outer"><div class"test inner1">定位实现水平垂直居中</div></div><style>.outer {width: 300px;height: 300px;border: 1px solid gray;margin: 100px auto 0;position: relative;}.te…...

Mybatis引出的一系列问题-动态 SQL

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架&#xff0c;你应该能理解根据不同条件拼接 SQL 语句有多痛苦&#xff0c;例如拼接时要确保不能忘记添加必要的空格&#xff0c;还要注意去掉列表最后一个列名的逗号。利用动态 SQL&#xff0c;可以彻底…...

Docker学习之构建Base Image

构建Base Image 目标是构建一个类似官方Hello world的镜像&#xff0c;需要配置好Docker运行环境。 创建目录&#xff0c;编写代码 创建并进入docker目录。 mkdir docker cd dockertouch hello.cvim hello.chello.c文件的内容如下&#xff1a; #include <stdio.h>in…...

SFM(Structure from Motion)和NeRF(Neural Radiance Fields)

SFM&#xff08;Structure from Motion&#xff09;和NeRF&#xff08;Neural Radiance Fields&#xff09;都是计算机视觉领域中的重要算法&#xff0c;用于不同的任务和应用。 SFM&#xff08;Structure from Motion&#xff09;&#xff1a; SFM是一种从图像序列中重建三维场…...

[Vue] Vue2和Vue3的生命周期函数

vue2有11个生命周期钩子, vue3有8个生命周期钩子 从vue创建、运行、到销毁总是伴随着各种事件, 创建、挂载、更新到销毁。 1.vue2系列生命周期 ⑴【beforecreate】实例创建前。 vue完全创建之前&#xff0c;会自动执行这个函数。 ⑵【Created】实例创建后。 这也是个生命…...

springboot集成分布式任务调度系统xxl-job(调度器和执行器)

一、部署xxl-job服务端 下载xxl-job源码 下载地址&#xff1a; https://gitee.com/xuxueli0323/xxl-job 二、导入项目、创建xxl_job数据库、修改配置文件为自己的数据库 三、启动项目、访问首页 访问地址&#xff1a; http://localhost:8080/xxl-job-admin/ 账号&#xff1…...

11_Vue3中的新的组件

1. Fragment 在Vue2中&#xff1a;组件必须要有一个跟标签在Vue3中&#xff1a;组件可以没有根标签&#xff0c;内部会将多个标签包含在一个Fragment虚拟元素中好处&#xff1a;减少标签层级&#xff0c;减少内存占用 2. Teleport 什么是Teleport?——Teleport 是一种能够将…...

详解推送Git分支时发生的 cannot lock ref 错误

在码云上建了一个项目仓库,分支模型使用 git-flow ,并在本地新建了一个功能分支 feature/feature-poll。后来在推送时发生错误,提示 cannot lock ref ...... 这样的错误信息。下面复盘一下具体过程和解决办法,以供参考。 在码云中建立仓库时,考虑到想按照 GitFlow 的模式…...

[国产MCU]-BL602开发实例-PWM

PWM 文章目录 PWM1、BL602的PWM介绍2、PWM驱动API介绍3、PWM使用示例脉冲宽度调制(Pulse width modulation,简称PWM)是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳定电源输出的改变。这种方…...

【JMeter】 使用Synchronizing Timer设置请求集合点,实现绝对并发

目录 布局设置说明 Number of Simulated Users to Group Timeout in milliseconds 使用时需要注意的点 集合点作用域 实际运行 资料获取方法 布局设置说明 参数说明&#xff1a; Number of Simulated Users to Group 每次释放的线程数量。如果设置为0&#xff0c;等同…...

动态网站建设第05章在线测试/武汉今日头条最新消息

简介 序列化是指将对象实例的状态存储到存储媒体的过程。在此过程中&#xff0c;先将对象的公共字段和私有字段以及类的名称&#xff08;包括类所在的程序集&#xff09;转换为字节流&#xff0c;然后再把字节流写入数据流。在随后对对象进行反序列化时&#xff0c;将创建出与原…...

静态网站开发课程模板/拼多多关键词排名查询

知名苹果分析师郭明錤预测苹果今年的iPhone14没有重大升级&#xff0c;它搭载的A16处理器将继续如A15那样小修小补&#xff0c;并且继续使用N5P工艺&#xff0c;原因在于它认为包括中国手机在内的众多安卓手机对它已完全没有威胁。A16处理器将与A15处理器一样采用台积电的N5P工…...

山东省建设厅定额网站/网站数据统计

在很多游戏中&#xff0c;需要使用到多点触摸功能&#xff0c;因此&#xff0c;Cocos2d-x也支持多点触摸。不过由于Cocos2d-x是跨平台的游戏引擎&#xff0c;所以必须考虑到不同平台的差异。由于不同平台&#xff08;iPhone、iPad、Android手机等&#xff09;支持的最大触摸点数…...

做网站要多少带宽/搜索引擎优化论文3000字

一、Python中6个序列的内置类型分别是什么&#xff1f;htmlPython包含6中内建的序列&#xff0c;即列表、元组、字符串、Unicode字符串、buffer对象和 xrange 对象。序列通用的操做包括&#xff1a;索引、长度、组合(序列相加)、重复(乘法)、分片、检查成员、遍历、最小值和最大…...

专业网站开发联系方式/网络市场调研的方法

邮件接收 思路 构造一个邮件对象就是一个Messag对象&#xff0c;如果构造一个MIMEText对象&#xff0c;就表示一个文本邮件对象&#xff0c;如果构造一个MIMEImage对象&#xff0c;就表示一个作为附件的图片&#xff0c;要把多个对象组合起来&#xff0c;就用MIMEMultipart对…...

网盘做网站/找代写文章写手

2019独角兽企业重金招聘Python工程师标准>>> 原文地址&#xff1a;Guava库学习&#xff1a;学习Guava Cache知识汇总 至此&#xff0c;我们结束了对Guava Cache 缓存机制的学习&#xff0c;在学习过程中&#xff0c;我们学习了如何简单的通过MapMaker创建最简单的Co…...