深入C语言之字节对齐 - [C 数据结构 算法]

2023-05-16

在C程序设计中我们经常需要用到一种数据类型的长度(占内存的字节数),例如:

   int *p = NULL;
   p = (int *)malloc(10*sizeof(int));/*用sizeof(int)来的到int类型的长度*/
   用sizeof可得到C语言中数据类型的长度,对基本数据类型而言,结果值很容易理解,但当sizeof的操作对象是一个结构类型时意想不到
麻烦就来了,其结果值经常与我们设想的不一样.为什么呢?现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的
变量的访问可以从任何地址开始,但实际情况并非如此.一些平台对某些特定类型的数据只能从某些特定地址开始存取,这就需要各种
类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放.这就是所谓的字节对齐.字节对齐是为了提高CPU的读取效
率.比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以
读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据.显然
在读取效率上下降很多.

   C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型
(如数组、结构、联合等)的数据单元.在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空 间.各个成员按
照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同.

   先让我们看几个例子吧(32bit,x86环境,gcc编译器):设结构体如下定义:
struct A
{
     int a;
     char b;
     short c;
};
struct B
{
    char b;
    int a;
    short c;
};
   现在已知32位机器上各种数据类型的长度如下:
char:         1(有符号无符号同)           short:       2(有符号无符号同) 
int:           4(有符号无符号同)           long:         4(有符号无符号同) 
float:         4                                double:8
   那么上面两个结构大小如何呢?结果是:sizeof(strcut A)值为8;sizeof(struct B)的值却是12。
   结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一个,B也一样;按理说A,B大小应该都是7字
节.之所以出现上面的结果就是因为编译器要对数据成员在空间上进行对齐.但然上面是按照编译器的默认设置进行对齐的结果,那么
我们是不是可以改变编译器的这种默认对齐设置呢,当然可以.例如:
#pragma pack (2) /*指定按2字节对齐*/
struct C
{
    char b;
    int a;
    short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐*/
sizeof(struct C)值是8。
修改对齐值为1:
#pragma pack (1) /*指定按1字节对齐*/
struct D
{
    char b;
    int a;
    short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐*/
sizeof(struct D)值为7。

   在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间.一般地,可以通过下面的方法来改变缺省的对界条
件:
· 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐.
· 使用伪指令#pragma pack (),取消自定义字节对齐方式.
另外,还有如下的一种方式:
· __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上.如果结构中有成员的长度大于n,则按照最大成员的长度来
对齐.
· __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐.
以上的n = 1, 2, 4, 8, 16... 第一种方式较为常见.

   那编译器是按照什么样的原则进行对齐的?先看四个重要的基本概念:
1.数据类型自身对齐值:对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节.

2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值.
3.指定对齐值:#pragma pack (value)时的指定对齐值value.
4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值.
有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式.有效对齐值N是最终用来决定数据存放地址方式的
值,最重要.有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后
顺序来排放的.第一个数据变量的起始地址就是数据结构的起始地址.结构体的成员变量要对齐排放,结构体本身也要根据自身的有效
对齐值调整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整数倍,结合下面例子理解).这样就不难理解上面的几个例
子的值了.
例子分析:
分析例子B:
struct B
{
    char b;
    int a;
    short c;
};
假设B从地址空间0x0000开始排放。该例子中没有定义指定对齐值,在笔者环境下,该值默认为4。第一个成员变量b的自身对齐值
是1,比指定或者默认指定对齐值4小,所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0。第二个成员变量a,其
自身对齐值为4,所以有效对齐值也为4,所以只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中,符合0x0004%
4=0,且紧靠第一个变量。第三个变量c,自身对齐值为2,所以有效对齐值也是2,可以存放在0x0008到0x0009这两个字节空间中,
符合0x0008%2=0。所以从0x0000到0x0009存放的都是B内容。再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所
以就是4,所以结构体的有效对齐值也是4。根据结构体圆整的要求,0x0009到0x0000=10字节,(10+2)%4=0。所以0x0000A
到0x000B也为结构体B所占用。故B从0x0000到0x000B共有12个字节,sizeof(struct B)=12;其实如果就这一个就来说它已将满足字
节对齐了,因为它的起始地址是0,因此肯定是对齐的,之所以在后面补充2个字节,是因为编译器为了实现结构数组的存取效率,试想如果
我们定义了一个结构B的数组,那么第一个结构起始地址是0没有问题,但是第二个结构呢?按照数组的定义,数组中所有元素都是紧挨
着的,如果我们不把结构的大小补充为4的整数倍,那么下一个结构的起始地址将是0x0000A,这显然不能满足结构的地址对齐了,因此
我们要把结构补充成有效对齐大小的整数倍.其实诸如:对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double
类型,其自身对齐值为4,这些已有类型的自身对齐值也是基于数组考虑的,只是因为这些类型的长度已知了,所以他们的自身对齐值
也就已知了。
同理,分析上面例子C:
#pragma pack (2) /*指定按2字节对齐*/
struct C
{
    char b;
    int a;
    short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐*/


第一个变量b的自身对齐值为1,指定对齐值为2,所以,其有效对齐值为1,假设C从0x0000开始,那么b存放在0x0000,符合
0x0000%1=0;
第二个变量,自身对齐值为4,指定对齐值为2,所以有效对齐值为2,所以顺序存放在0x0002、0x0003、0x0004、0x0005四个连
续字节中,符合0x0002%2=0。
第三个变量c的自身对齐值为2,所以有效对齐值为2,顺序存放在0x0006、0x0007中,符合0x0006%2=0。所以从0x0000到
0x00007共八字节存放的是C的变量。又C的自身对齐值为4,所以C的有效对齐值为2。又8%2=0,C只占用0x0000到0x0007的八个
字节。所以sizeof(struct C)=8。

   最后看一个Intel和微软和本公司同时出现的面试题,来练习一下:
#pragma pack(8)
struct s1{
   short a;
   long b;
};
struct s2{
   char c;
   s1 d;
   long long e;
};
#pragma pack()
问 
1.sizeof(s2) = ?
2.s2的c后面空了几个字节接着是d?
结果如下:sizeof(S2)结果为24。s2的c后面空了3个字节接着是d。

分析:
   S1中,成员a是1字节默认按1字节对齐,指定对齐参数为8,这两个值中取1,a按1字节对齐;成员b是4个字节,默认是按4字节对齐,这时就
按4字节对齐,所以sizeof(S1)应该为8;
   S2 中,c和S1中的a一样,按1字节对齐,而d 是个结构,它是8个字节,它按什么对齐呢?对于结构来说,它的默认对齐方式就是它的所有成
员使用的有效对齐值中最大的一个,S1的就是4.所以,成员d就是按4字节对齐.成员e是8个字节,它是默认按8字节对齐,和指定的一样,
所以它对到8字节的边界上,这时,已经使用了12个字节了,所以添加了4个字节的空,从第16个字节开始放置成员e。这时,长度为24,已
经可以被8(成员e按8字节对齐)整除。这样一共使用了24个字节。
                      a         b
S1的内存布局:11**,1111,
                      c         S1.a S1.b d
S2的内存布局:1***,11**,1111,****11111111

http://gotousa.ycool.com/post.2864740.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入C语言之字节对齐 - [C 数据结构 算法] 的相关文章

  • 知识图谱构建技术

    知识图谱的构建技术包括知识抽取 知识融合 知识加工和知识更新等 图1 知识图谱构建技术流程图 1 1 知识抽取 知识抽取就是自动化或半自动化的从原始数据中获得实体 关系及属性等可用知识单元 早期是基于规则的知识抽取 xff0c 通过人为预先
  • 答“我们的团队项目是否有大泥球?”

    总结了一下 xff0c 产生大泥球的主要原因有下面这些原因 xff1a xff08 1 xff09 一次性代码 xff08 2 xff09 碎片式增长 xff08 3 xff09 为了让软件不出问题 xff08 4 xff09 Copy p
  • JSON是什么

    提起 JSON xff0c 作为如今最受欢迎的数据交换格式 xff0c 可以说是无人不知 无人不晓了 JSON 全称 JavaScript Object Notation xff08 JS 对象简谱 xff09 xff0c 自诞生之初的小目
  • <操作系统> 售票员司机问题(信号量) C语言实现

    问题描述 xff1a 思路 xff1a 代码 xff1a span class token macro property span class token directive keyword include span span class
  • 展锐T7520(ANDROID 11) boot.img解包

    1 make unpack bootimg 或者 prebuilts build tools linux x86 bin ninja f out combined ninja unpack bootimg 2 export PATH 61
  • 连通图(求桥的数量)

    桥 xff1a 连通图中存在的必经之路 xff0c 我们成为桥 xff0c 如果把此路断开 xff0c 连通图便会变成两个图 判断是否是桥的方式 low v gt dfn u 题目链接 AC代码 xff1a include lt bits
  • Lotti引发的java.lang.StackOverflowError

    在项目中将lottie从2 8 0版本进行升级至4 2 0版本后 xff0c 突然出现堆栈内存错误 xff0c 最后查找原因是因为在onAnimationEnd 回调方法中调用resumeAnimation 方法 xff0c 而在resum
  • Ubuntu 服务器操作笔记 之 安装SSH

    1 gt sudo apt get install openssh server 安装SSH 2 gt sudo ps e grep ssh 查询 SSH是否启动 3 gt sudo etc init d ssh start 如果没有 则启
  • 分析APP的安装流程 API29

    先总结一下安装流程 xff0c 以及比较重要的类 PackageInstallerActivity java xff1a 在文件管理器里点击apk后就会调用该类 xff0c 主要用于显示要安装的apk的一些权限信息 InstallAppPr
  • Linux下安装KDE桌面环境

    Linux中有许多桌面应用环境 xff0c 在这其中除了deepin的dde桌面之外 xff0c 界面和功能都很强大好用的就是kde了 下面我来分享一下我的kde安装经过 我的Linux发行版是deepin的v15 11版本 xff0c 尝
  • json去掉指定字段

    lt dependency gt lt groupId gt org json lt groupId gt lt artifactId gt json lt artifactId gt lt version gt 20160810 lt v
  • mac 安装 man中文文档

    配置环境 brew install autotoolsbrew install python3brew install openccbrew install automake 下载源码 https github com man pages
  • 【NLP最佳实践】Huggingface Transformers实战教程

    内容简介 x1f917 手把手带你学 xff1a 快速入门Huggingface Transformers 和鲸链接 xff1a https www heywhale com home activity detail 61dd2a3dc23
  • visual studio配置clang开发环境

    一 安装环境 1 下载visual studio 2 选择工作负载 xff0c 使用c 43 43 的桌面开发 3 选择单个组件 xff0c 搜索clang xff0c 勾选两个组件 4 点击安装 等待安装完成 二 测试环境 xff1a 在
  • DeepSpeed-Chat:最强ChatGPT训练框架,一键完成RLHF训练!

    https github com microsoft DeepSpeedExamples tree master applications DeepSpeed Chat 一个快速 负担得起 可扩展和开放的系统框架 xff0c 用于实现端到端
  • BigCode开放性能超越Copilot的代码生成模型Starcoder

    BigCode释出高效能程式码生成模型StarCoderBase xff0c 与为Python调校的StarCoder xff0c 效能超越GitHub Copilot初期版本所用的OpenAI code cushman 001模型 xff
  • 【LLM系列之FLAN-T5/PaLM】Scaling Instruction-Finetuned Language Models

    论文题目 xff1a Scaling Instruction Finetuned Language Models 论文链接 xff1a https arxiv org pdf 2210 11416 pdf github链接 xff1a ht
  • LlamaIndex :面向QA 系统的全新文档摘要索引

    在这篇博文中 xff0c 我们介绍了一种全新的 LlamaIndex 数据结构 xff1a 文档摘要索引 我们描述了与传统语义搜索相比 xff0c 它如何帮助提供更好的检索性能 xff0c 并通过一个示例进行了介绍 背景 大型语言模型 LL
  • html中各种hr样式

    第一种 lt hr style 61 34 height 2px border none border top 2px dotted 185598 34 gt height 2px 是hr的高度 border none 是没有边框 bord
  • Python爬虫系列(五)360图库美女图片下载

    这几天终于忙完毕设和学校的事情 xff0c 终于有时间来写Python了 xff08 xffe3 xffe3 xff09 前些天在群里看到有人讨论这个360美女图库 的爬取 自己今天也尝试下 xff08 蛮简单 xff09 因为这个网站是下

随机推荐

  • Python 过滤字母和数字

    实例1 crazystring 61 39 dade142 0142f ad 39 只保留数字 new crazy 61 filter str isdigit crazystring print 39 39 join list new cr
  • Python人工智能之图片识别,Python3一行代码实现图片文字识别

    自学Python3第5天 xff0c 今天突发奇想 xff0c 想用Python识别图片里的文字 没想到Python实现图片文字识别这么简单 xff0c 只需要一行代码就能搞定 作者微信 xff1a 2501902696 from PIL
  • Contrastive Loss(对比损失)

    Contrastive Loss 在传统的siamese network中一般使用Contrastive Loss作为损失函数 xff0c 这种损失函数可以有效的处理孪生神经网络中的paired data的关系 siamese networ
  • maven详细配置

    Maven 本质 xff1a 项目管理工具 可以做到整体编译 测试 xff0c 快速打包部署 作用 xff1a 项目构建 xff0c 提供标准的构建方式依赖管理 xff0c 避免版本冲突 生命周期 xff1a mvn clean 清理编译项
  • clang ast基本命令的使用

    1 生成二进制文件 clang emit ast input cpp 需要二进制文件相应的查看器才可以读 xff0c txt打开乱码了 2 直接在控制台打印输出 clang Xclang ast dump fsyntax only inpu
  • unreferenced local variable

    有时候编译程序的时候会发现下面的错误 warning C4101 39 n 39 unreferenced local variable 其实就是程序里面定义了变量但是没有使用 xff0c 才会有这样的警告 解决方法就是像下面这样定义 in
  • 来自一位女程序员8年的总结。

    8年了 xff0c 从来没有像今天说总结这一下 我认为这是我的一个进步吧 8年 xff0c 包括上北大青鸟培训的2年 xff0c 然后6年的工作 xff0c 换了很多家公司 有个人原因也有公司原因 先说一下培训的那2年 xff0c 我们学习
  • Nginx配置重定向和反向代理(转发)

    重定向 地址重定向 xff1a 是指当使用者浏览某个网址时 xff0c 将他导向到另一个网址的技术 常用在把一串很长的网址 xff0c 转成较短的网址 因为当要传播某网站时 xff0c 常常因为网址太长 xff0c 不好记忆 xff1b 又
  • intelliJ idea创建分层的项目结构

    原文地址 xff1a http www yanwushu com post 35 html 本文使用intelliJidea 14 在idea中创建一个分层 xff08 视图层 业务逻辑层 数据访问层 xff09 的项目步骤如下 xff1a
  • 新电脑将软件安装到D盘的操作说明

    新电脑将软件安装到D盘的操作说明 每次安装软件 xff0c 都会默认安装到C盘 xff0c C盘满了 xff0c 电脑就会变卡 xff0c 我们应该避免这种情况 一 下载软件前要做的事 我们应该避免使用软件管家等工具 xff0c 因为它们的
  • 敏捷开发快速入门(四):Scrum开发流程

    文章目录 Scrum概述Scrum中三个角色Product Owner xff08 产品负责人 xff09 职责Scrum Master xff08 教练 xff09 职责Scrum Team xff08 开发团队 xff09 职责 Scr
  • Java命名规范【全】

    前言 本文根据本人日常的学习等 xff0c 总结出来的Java中的命名规范 基本上概括所有 喜欢的话记得点个赞 xff0c 收藏哟 包 xff08 Package xff09 命名规范 1 使用小写英文字母进行命名 2 多层包之间用点进行分
  • iOS包重签名工具,ipa文件重签名,快速签名,SignTool签名工具,好用的签名工具,App重签名

    重要 xff01 重要 xff01 重要 xff01 xff01 xff01 由于之前使用免费的服务器 xff0c 大概8月20号左右 xff0c 服务器已无法访问 xff0c 造成App无法使用 xff1b 现已把服务器移到阿里云 xff
  • windows server2008环境下mpirun运行报错:应用程序无法正常启动(0xc000007b)的解决方案

    原因是缺少运行库 xff0c 或者运行库32 64版本问题 xff0c 安装 微软常用运行库合集 Microsoft Runtimes AIO x86 43 x64 即可解决 https www flighty cn html soft 2
  • system.img解包打包

    在做copy machine的img中 xff0c 遇到不能重新build的情况 xff08 会改变信息 xff09 xff0c 这个时候可以将原来生 成的这些 img xff08 system img persist img cache
  • jmeter多用户并发测试

    0 总体结构 1 测试计划 gt 添加 gt 线程 xff08 用户 xff09 gt 线程组 2 线程组 gt 添加 gt 取样器 gt HTTP请求 注意本项目登录请求为GET 其他项目可能为POST 3 HTTP请求 gt 添加 gt
  • 练习java文档java.util.logging.ConsoleHandler

    ConsoleHandler 方法 close 相当于flush publish span class token keyword import span span class token namespace java span class
  • 轻量级JavaEE第1章课后习题1

    1 为什么说经典javaee开发和运行成本会比轻量级javaee更高 xff1f 答 可能是因为专业的JavaEE服务器要钱 xff0c 而简单的Web服务器不需要钱 2 EAO和DAO的区别是什么 xff1f 什么叫实体 Entity x
  • 请教:如何知道当前所用的gcc调用的是哪个版本的glibc库?及这个glibc库的位置?谢谢!

    http topic csdn net u 20090608 15 36bf4a6c cdf5 4e05 90f3 c0ac0d3f6743 html 6533 请教 xff1a 如何知道当前所用的gcc调用的是哪个版本的glibc库 xf
  • 深入C语言之字节对齐 - [C 数据结构 算法]

    在C程序设计中我们经常需要用到一种数据类型的长度 占内存的字节数 例如 int p 61 NULL p 61 int malloc 10 sizeof int 用sizeof int 来的到int类型的长度 用sizeof可得到C语言中数据