结构体边界对齐

结构体边界对其是一个老生常谈的话题了,网上的解释非常多,但大多偏重于讲步骤,对于每一步的原因都有点不清楚的地方,下面结合网上的讲解和自己的理解谈谈结构体对齐,不一定正确。

1.什么是结构体对齐。

struct A{

char  a;

char b;

int c;

char  d;

}

对于上面的这个结构体,假设机器字长32位(4字节),那么该结构体变量占用的空间并非1+1+4+1=7,而是1+3+4+1+3=12。编译器自动将c的起始位置调整到第4个字节处,并在结构体最后加了3个字节,这种编译器调整变量内存地址的现象就是结构体对齐。

2.为什么要结构体对齐。

cpu的寻址并不是可以随机访问的,我们把一个字节看作一个内存单元,给每个内存单元添加连续的标号,构成了内存地址,cpu对内存的访问限制取决于其机器字长,一般来说,若机器字长为N,那cpu访问内存时每次都是读取以N的整数倍为地址的连续N个内存单元(这个好像在计算机组成原理cpu寻址那块也有体现),所以,以结构体A为例,若其变量的成员变量c的存储位置不进行调整,仍然从第3个字节开始存储,那么cpu要访问a就要寻址两次,第一次访问地址为0的连续4个内存单元,后2个单元的值是c的一部分,然后还要访问地址为4的连续4个内存单元,前2个单元为c的一部分。若进行内存对齐,将变量c放在机器字长整数倍的位置,则只需一次访问即可。

3.一点思考。

上面的讲的对齐方法有一点没有提到,既然将变量c放在机器字长的整数倍的位置上,为什么变量b没有这样做,将所有变量都按机器字长的整数倍存储不就行了吗。我的理解是,在访问内存单元时,最大的开销在于总线的占用和传输,至于在cpu内部对数据的处理相比之下开销几乎不存在,故对于长度小于机器字长的变量来说,其存储位置只要满足是自己长度的整数倍即可,这样就能保证cpu能一次内存访问就获得全部数据(感觉是这样的,因为所有基础变量包括机器字长相互之间是整除与被整除的关系,长度规律是1,2,4,8,16,32……,虽然不会严格证明,但想不出满足该规律结果还分两次访问的反例),然后再cpu内部经过极小的代价将其提取出来即可,这样时间成本相比按机器字长整数倍存储只增加了一点点(因为都是只靠一次内存访问就能获取数据,而cpu内部处理的花费很小),但是节省了存储空间,试想若变量很多,那么节省的空间是很可观的。

4.总结结构体成员对齐的步骤

确定机器字长,结构体内每个变量与机器字长比较,取较短的那个值作为各自的对其系数进行对齐,这里要注意一点,最后要取结构体内最长变量的长度与机器字长中较小的那个数对结构体大小做圆整,这样是为了保证使用结构体数组时使每个数组元素都能对齐。

时间: 2024-10-15 05:18:15

结构体边界对齐的相关文章

结构体字节对齐

结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐. 内存对齐的原因: 1)某些平台只能在特定的地址处访问特定类型的数据: 2)提高存取数据的速度.比如有的平台每次都是从偶地址处读取数据,对于一个int型的

C语言 结构体(联合体)对齐规则

/* 结构体(联合体)对齐规则 */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* * 原则1.第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储). * 原则2.结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最宽基本类型大小的整数倍地址开始存储. *原则3.结构

结构体字节对齐问题(转)

原文出处:http://wenku.baidu.com/view/019e26b765ce0508763213e2.html 初学C,对结构体的使用sizeof计算所占字节数不是很明白,看了此篇文章,终于豁然开朗,转载过来,方便以后温故. #include<stdio.h> struct a {   char no[10];   int p;   long int pp;   unsigned int ppp;   char x;   float y;   double h; }xy; voi

结构体嵌套对齐

64 位的优点:64 位的应用程序可以直接访问 4EB 的内存和文件大小最大达到4 EB(2 的 63 次幂):可以访问大型数据库.本文介绍的是64位下C语言开发程序注意事项. 1. 32 位和 64 位C数据类型 32和64位C语言内置数据类型,如下表所示: 上表中第一行的大写字母和数字含义如下所示:I表示:int类型L表示:long类型P表示:pointer指针类型32表示:32位系统64表示64位系统如:LP64表示,在64位系统下的long类型和pointer类型长度为64位.64位Li

结构体的对齐访问

什么是结构体对齐访问(1)结构体中元素的访问其实本质上还是用指针方式,结合这个元素在整个结构体中的偏移量和这个元素的类型来进行访问的.(2)但是实际上结构体的元素的偏移量比较复杂,因为结构体要考虑元素的对齐访问,所以每个元素时间占的字节数和自己本身的类型所占的字节数不一定完全一样.(譬如char c实际占字节数可能是1,也可以是2,也可能是3,也可以能4····)(3)一般来说,我们用.的方式来访问结构体元素时,我们是不用考虑结构体的元素对齐的.因为编译器会帮我们处理这个细节.但是因为C语言本身

C++结构体字节对齐

本站文章均为Jensen抹茶喵原创,转载务必在明显处注明:转载自[博客园] 原文链接:http://www.cnblogs.com/JensenCat/p/4770171.html 直接上源码吧!~ 这里是头文件结构的定义: 一个非字节对齐结构体_tagTest2 一个字节对齐_tagTest3 (使用#pragma pack(push,1)来使字节以1个来对齐 , 使用#pragma pack(pop)来还原默认) 1 #pragma once 2 3 4 struct _tagTest1 5

结构体 字节对齐

转自:http://www.cnblogs.com/longlybits/articles/2385343.html   (有改动) 内存对齐 在用sizeof运算符求某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列,而不是简单地顺序排列,这就是内存对齐. 内存对齐的原因: 1)某些平台

C#调用C++ 平台调用P/Invoke 结构体--内存对齐方式、union封装【七】

[1]内存对齐方式 C++代码: #pragma pack(push) #pragma pack(1) typedef struct _testStru2 { int iVal; char cVal; __int64 llVal; }testStru2; #pragma pack(pop) EXPORTDLL_API void Struct_PackN( testStru2 *pStru ) { if (NULL == pStru) { return; } pStru->iVal = 1; pS

C语言中改变结构体的对齐方式

C语言中默认是以结构体中最长的数据类型为对齐标准如 typedef struct _NODE { short a; int b; char c; }NODE; 会以int,即4字节为对齐标准,此时sizeof(NODE)=12 可以使用#pragma pack(n)改变对齐方式.编译器会从“n”和”结构体中最长的数据类型长度“中选较小的那个作为对齐标准 如#pragma pack(1),相关于取消对齐,1B对齐,此时sizeof(NODE)=7