`
ChuanSu
  • 浏览: 53838 次
  • 性别: Icon_minigender_1
  • 来自: 石家庄
社区版块
存档分类
最新评论

C/C++ Data alignment 及 struct size深入分析

阅读更多
C语言,在对一个 struct variable使用sizeof operator(操作符)的时候,往往得到的结果并不是我们想象中——struct内所有member的size之和。

当清楚了什么是Data alignment(数据对齐),对这个问题就豁然开朗了。

Data Alignment

在C/C++,甚至所有programming language中,每个Data object,更确切的说是 每个variable都有两个属性 :
  • value (自身的值)
  • memory address(其内存地址)
对每个variable的分析,都是基于内存分析的。所以,分析variable自身value的时候,又是分析 其在内存中的存储形式.所以更确切的是
     Variable Properties 
  • bit pattern
  • memory address
往往variable最重要的属性,是其内存地址。这也是为什么 在C/C++中,指针,pointer是如此的强大。

Data Alignment 并非针对 Data 本身,而是Data(Variable)的内存地址 。在 MSDN 对 Alignment做出定义,其第一句话便是
Alignment is a property of a memory address

以一张表格来展现32-bit machine 的内存结构



计算机中,内存是由大量的,连续的,可寻址的或编了号的memory cells(内存单元)构成。每个memory cell 占1 byte。

假如上述表格 bank0的address 为X,那么bank1,bank2,bank2的地址分别为X+1,X+2,X+2。

CPU在处理内存数据时,并非一次提取一个memory cell,一般提取一组相邻内存单元。在32-bit machine,CPU一次从内存中读取 4个连续的memory cell(4-byte) 。所以在此表格中,4 byte chunk(4字节流) 为一个读取周期。在读取一个int型 数据时,仅仅需要一个周期(int 占4 byte)。读取Double型,则需要2个读取周期。表格(D0-D31,32-bit)表示一个内存周期。如果是8-bit machine 即1字长(D0-D7),则需要4个周期来读取一个integer。


说了一些基本的内存知识,接下来看看 MSDN对Alignment的定义是怎么样的
MSDN 写道

Alignment is a property of a memory address, expressed as the numeric address modulo a power of 2. For example, the address 0x0001103F modulo 4 is 3; that address is said to be aligned to 4n+3, where 4 indicates the chosen power of 2. The alignment of an address depends on the chosen power of two. The same address modulo 8 is 7.

An address is said to be aligned to X if its alignment is Xn+0.

CPUs execute instructions that operate on data stored in memory, and the data are identified by their addresses in memory.

仔细理解下,可以总结为,当向内存中放入一个数据(variable)时,此数据的地址,严格来说是offset,起始地址,必须是此数据的Alignment的整数倍。即上述 Xn+0。
对于每种类型的数据,都有其自身的Alignment

Data Type Alignments(in Bytes)
   char            1         
   short           2         
   int             4         
   float           4         
   double        4 or 8      


例如char 的offset可以在bank0,bank1,bank2,bank3任意一个(这里为了方便,假设bank0初始位置的address为0,依次类推)。short型的2 bytes只能存储在 bank0-bank1或者bank2-bank3,假如其offset在bank1上,即存储在bank1-bank2,那么此address为奇数,并非short alinment的整数倍。


int型,offset只能在bank0上,在其他位置,都不会是4的整数倍。如果一个int型的整数,0xABCDEF,在内存中的起始位置在 bank1 上会发生什么呢?



可以看到此integer的addres并非是4的整数倍,跨过两行,那么在读取此data时,就需要两个读取周期了。

所以data alignment正是用来处理variable在这些bank中的存储方式。以避免发生此情况。在上表中,此整数的地址为5,5=4n+1,按照MSDN定义来说,此整数的alignment为1.但是int 型的alignment应该是4。所以这种情况又称为misaligned

Data Structure Padding


在C/C++中,因为对variable都有alignment的要求,所以在struct中,每一个member都要遵循alignment的要求。就拿 MSDN中的一个例子,来谈下struct的alignment
struct x_
{
   char a;     // 1 byte
   int b;      // 4 bytes
   short c;    // 2 bytes
   char d;     // 1 byte
} MyStruct;


同上述表格一样,struct中的member在内存中,是由下至上allocate的。

char a的起始位置在bank0,假如addrees为0;

int b,是不可以在bank1,bank2,bank3,这样b的offset为奇数,不是4的整数倍,所以只能在bank4,其4 bytes在 bank4-bank5-bank6-bank7;

那么在char a与int b之间需要填补3个无意义的byte。来满足int b的对齐方式。

short c是可以在bank8的,8为2的整数倍。所以b,c间无需要填补。那么short c 存储在 bank8-bank9。

char d可以存储在任何位置。那么char d 则存储在 byte10.

最后需填补1 byte

padding byte   char d      short c    short c    
int b          int  b      int   b    int   b    
padding bytepadding bytepadding byte  char  a    


在最后填补一个byte的原因是:
在struct的member的alignment中,找到alignment的最大值(此处为4 bytes),在struct的最后一个member填补 padding bytes使整个struct的size 为此aligment(4 bytes)的整数倍。

所以上述struct 在内存中的实际形式为
// Shows the actual memory layout
struct x_
{
   char a;            // 1 byte
   char _pad0[3];     // padding to put 'b' on 4-byte boundary
   int b;            // 4 bytes
   short c;          // 2 bytes
   char d;           // 1 byte
   char _pad1[1];    // padding to make sizeof(x_) multiple of 4
}


此struct的size为12 bytes,而不是8 bytes。


Resource

http://msdn.microsoft.com/en-us/library/ms253949.aspx
http://en.m.wikipedia.org/wiki/Data_structure_alignment#section_5
http://www.geeksforgeeks.org/archives/9705
http://www.songho.ca/misc/alignment/dataalign.html
  • 大小: 11.2 KB
  • 大小: 4.9 KB
分享到:
评论
1 楼 NonMac 2016-09-11  
良心博客,谢谢博主~~

相关推荐

    Data Alignment in SEE、SSE2

    例如,在使用Intel C/C++ Compiler和Microsoft Visual C++ Compiler共同构建应用程序时,不同编译器之间的对齐规则可能存在差异,导致程序行为不一致。 1. **混合构建应用**:在混合使用VC++和Intel C++ Compiler ...

    Google C++ Style Guide(Google C++编程规范)高清PDF

    Parameters to C/C++ functions are either input to the function, output from the function, or both. Input parameters are usually values or const references, while output and input/output parameters ...

    《你必须知道的495个C语言问题》

    《你必须知道的495个C语言问题》结构清晰,讲解透彻,是各高校相关专业C语言课程很好的教学参考书,也是各层次C程序员的优秀实践指南。 -----------------------------------------------------------------------...

    华为编程开发规范与案例

    7、用于控制条件转移的表达式及取值范围是否书写正确 第20页 【案例1.7.1】 第20页 【案例1.7.2】 第21页 【案例1.7.3】 第22页 8、条件分支处理是否有遗漏 第24页 【案例1.8.1】 第24页 9、引用已释放的资源 第26页...

    稳压罐sw16_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    稳压罐sw16_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    基于递推最小二乘法的永磁同步电机参数辨识及其MATLAB仿真

    内容概要:本文详细介绍了利用递推最小二乘法(RLS)进行永磁同步电机参数辨识的方法及其MATLAB仿真过程。首先解释了RLS算法的优势,如不需要概率模型、计算量适中以及适用于嵌入式系统的实时参数更新。接着展示了将电机电压方程转换为标准形式Y=φθ的具体步骤,并提供了核心的RLS迭代代码。文中还讨论了仿真过程中的一些关键技术细节,如遗忘因子的选择、协方差矩阵的初始化和更新方式、电流信号的处理方法等。最终给出了仿真结果,显示电阻和电感的辨识误差分别达到了0.08%和0.12%,并指出了实际应用中需要注意的数据同步和数值稳定性问题。 适合人群:从事电机控制研究的技术人员、研究生及以上学历的学生。 使用场景及目标:①帮助研究人员理解和掌握RLS算法在电机参数辨识中的应用;②提供详细的仿真代码和配置建议,便于快速搭建实验环境;③指导如何优化算法性能,提高参数辨识精度。 其他说明:本文不仅涵盖了理论推导,还包括了大量的实践经验分享和技术细节探讨,有助于读者全面理解RLS算法的实际应用。同时,文中提到的仿真方案可以方便地移植到DSP平台,进一步扩展了其实用价值。

    零起点Python大数据与量化交易

    零起点Python大数据与量化交易

    管道清污机器人sw16可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    管道清污机器人sw16可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    电路仿真:数字电路仿真.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

    电能质量分析:电压暂降与中断分析.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

    thai-scalable-garuda-fonts-0.6.5-1.el8.x64-86.rpm.tar.gz

    1、文件说明: Centos8操作系统thai-scalable-garuda-fonts-0.6.5-1.el8.rpm以及相关依赖,全打包为一个tar.gz压缩包 2、安装指令: #Step1、解压 tar -zxvf thai-scalable-garuda-fonts-0.6.5-1.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm

    基于ABAQUS的滑坡与沉降对埋地管道影响的有限元分析及应用

    内容概要:本文详细介绍了利用ABAQUS进行滑坡和沉降对埋地管道影响的有限元分析方法。主要内容涵盖了几何建模、材料属性定义、接触设置、边界条件与加载等方面的技术细节。通过具体的Python脚本示例展示了如何构建模型,并深入探讨了滑坡和沉降条件下管道的应力、应变分布及其潜在破坏机制。此外,还分享了一些实战经验和优化技巧,如材料模型选择、接触条件设置、边界条件处理等,强调了这些因素对结果准确性的重要影响。 适合人群:从事地下管道工程设计、施工及维护的专业技术人员,尤其是那些希望深入了解滑坡和沉降对管道影响的研究人员和技术专家。 使用场景及目标:适用于评估和预测滑坡和沉降对埋地管道造成的力学响应,帮助工程师们更好地理解和应对复杂的地质灾害环境,从而提高管道系统的安全性与稳定性。 其他说明:文中提供的Python代码片段仅为示意,具体实施时需结合ABAQUS的实际接口和项目需求进行适当调整。同时,对于大规模模型的计算,建议使用高性能计算资源以确保效率和精度。

    Java实习一天高频面试突击!最常见的几种面试题型!!!

    Java一天面试突击,迅速掌握Java常见面试题

    莲子去壳机设计模型SW10_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    莲子去壳机设计模型SW10_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    MFRC-522+RC522+RFID射频+IC卡感应模块

    MFRC-522+RC522+RFID射频+IC卡感应模块

    学术研究学术研究提示设计50招:从论文撰写到润色降重的全方位指南学术研究中常见的

    内容概要:《学术研究提示设计 50 招》是一份详尽的指南,旨在帮助研究人员提高学术写作和研究效率。该文档涵盖了从论文撰写、润色、翻译、查重降重、参考文献管理、投稿审稿到文献阅读等多个方面的具体操作指令。每一章节均针对特定任务提供了详细的步骤和注意事项,例如如何撰写标题、摘要、致谢,如何进行英文润色、中英翻译,以及如何优化逻辑结构等。文档还介绍了如何利用AI工具进行文献分析、术语表提取和研究方向探索等内容,为研究者提供了全面的支持。 适合人群:适用于学术研究人员,特别是那些需要撰写、润色和提交学术论文的研究者,包括研究生、博士生及高校教师等。 使用场景及目标:① 提供一系列具体的指令,帮助研究者高效完成论文的各个部分,如撰写标题、摘要、致谢等;② 提供润色和翻译的详细指导,确保论文语言的准确性和专业性;③ 提供查重降重的方法,确保论文的原创性;④ 提供参考文献管理和投稿审稿的指导,帮助研究者顺利发表论文;⑤ 利用AI工具进行文献分析、术语表提取和研究方向探索,提高研究效率。 阅读建议:此资源不仅提供了具体的指令和方法,更重要的是引导研究者如何思考和解决问题。因此,在学习过程中,不仅要关注具体的步骤,还要理解背后的原理和逻辑,结合实际案例进行实践和反思。

    项目optionc-20250409

    项目optionc-20250409

    2023年c语言程序设计基本概念考点归纳.doc

    2023年c语言程序设计基本概念考点归纳.doc

    电能质量仿真:谐波分析与仿真.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

    基于Matlab的模拟与数字滤波器设计:IIR、FIR及经典滤波器类型的实战详解

    内容概要:本文详细介绍了使用Matlab进行模拟和数字滤波器设计的方法,涵盖了巴特沃斯、切比雪夫等多种经典滤波器类型。首先讲解了模拟滤波器的设计,如巴特沃斯滤波器的通带平坦性和切比雪夫滤波器的通带波纹特性,并提供了具体的代码示例。接着讨论了数字滤波器的设计,包括IIR滤波器的递归特性和FIR滤波器的线性相位特性,同样附有详细的代码实现。文中还特别强调了不同类型滤波器之间的转换方法以及设计过程中常见的注意事项,如频率归一化、阶数选择等。最后推荐了一些实用的Matlab工具,如fvtool和FDATool,帮助用户更直观地理解和调试滤波器设计。 适合人群:具有一定信号处理基础和技术背景的研究人员、工程师及学生。 使用场景及目标:适用于需要进行滤波器设计的实际工程应用,如通信系统、音频处理等领域。目标是让读者掌握滤波器设计的基本原理和具体实现方法,能够独立完成滤波器的设计和调试。 其他说明:文章不仅提供了理论知识,还通过大量实例代码帮助读者更好地理解和应用所学内容。建议读者在实践中多尝试不同的参数配置,以加深对滤波器特性的理解。

Global site tag (gtag.js) - Google Analytics