`
蒙面考拉
  • 浏览: 160648 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

内存对齐问题

 
阅读更多

1.内存数据对齐的原因:

    无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。

2.数据对齐原则:

    1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节, 则要从4的整数倍地址开始存储),基本类型不包括struct/class/uinon。

    2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部"最宽基本类型成员"的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)。

    3、收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的"最宽基本类型成员"的整数倍.不足的要补齐.(基本类型不包括struct/class/uinon)。

    4、sizeof(union),以结构里面size最大元素为union的size,因为在某一时刻,union只有一个成员真正存储于该地址。

3.具体实例:

 

#include <iostream>   
using namespace std;  
union a  
{  
 int a_int1;  
 double a_double;    //8字节   
 int a_int2;  
 char ch;  
                     //由原则4,a的大小为8   
};  
struct b  
{  
 a a1;              //[0]...[7] ,   
 char y;            //[8]   
                    //由原则3,"最宽基本类型成员"为a中的double,从而b的大小为8的整数倍,所以b的大小为16   
};  
class c  
{  
 int c_double;      //[0]...[4]   
 b b1;              //[8]...[23]   原则2:与b的内部的最大元素的整数倍开始存储   
 char ch;           //[24]   
                    //由原则3,"最宽基本类型成员"为b中,即b里面a的double,c的大小为8的整数倍,所以c的大小为32   
};  
struct usc  
{  
    char ch;        //[0]   
    b b2;           //[8]...[23]   原则2:与b的内部的最大元素的整数倍开始存储   
    a a2;           //[24]...[31]      
    c c2;           //[32]...[63]   
    char ch1;       //[64]   
                    //"最宽基本类型成员"为a中的double 或者 即b里面a的double 或者 c里面的b里面的double   
                    //由原则3,usc的大小为8的整数倍,所以usc的大小为72   
};  
void main()  
{  
    cout<<"sizeof(a)= "<<sizeof(a)<<endl;  
    cout<<"sizeof(b)= "<<sizeof(b)<<endl;    
    cout<<"sizeof(c)= "<<sizeof(c)<<endl;                                               
    cout<<"sizeof(usc)= "<<sizeof(usc)<<endl;    
}  
 

总结:

       从“struct/class以及union内存对齐原则”可以得出:在struct/class/union中定义变量时,长度小的变量先定义,长度大的变量后定义,可以节省内存。

4.#pragma pack()

在代码前加一句#pragma pack(1),#pragma pack(1)是告诉编译器,所有的对齐都按照1的整数倍对齐,换句话说就是没有对齐规则.
 

5.位域(特例)

 

#include<iostream>
using namespace std;
#pragma pack(1)
struct A 
{ 
 //unsigned short i:8;
 char t:4; //位域的意思:表示t占4个位
 char k:4;
 unsigned long m; 
 //char k:4; 
 unsigned short i:8;
 //unsigned short j:8;
} ;
#pragma pack()
int main(){
	A b;
	cout<<sizeof(b)<<endl;
	system("pause");
	return 1;
}

 不考虑边界对齐,大小为7,tk他俩占第一个字节,i占第二个字节,m从四字节开始占四个字节,问题是m为什么不从第三字节开始:是因为第二三字节的short被划分为2个字节类型的位模式了,m改为unsigned short m:8;就可以从第三字节开始了。

同理:

 

#include<iostream>
using namespace std;
#pragma pack(1)
struct A 
{ 
 //unsigned short i:8;
 char t:4; 
 //char k:4;
 unsigned long m; 
 char k:4; 
 unsigned short i:8;
 //unsigned short j:8;
} ;
#pragma pack()
int main(){
	A b;
	cout<<sizeof(b)<<endl;
	system("pause");
	return 1;
}

 输出就是8.

 

#include<iostream>
using namespace std;
#pragma pack(1)
struct A 
{ 
 //unsigned short i:8;
 char t:4; 
 char k:4;
 unsigned long m; 
 //char k:4; 
 unsigned short i:8;
 unsigned short j:8;
} ;
#pragma pack()
int main(){
	A b;
	cout<<sizeof(b)<<endl;
	system("pause");
	return 1;
}

 输出是7.

 

#include<iostream>
using namespace std;
#pragma pack(1)
struct A 
{ 
 unsigned short i:8;
 char t:4; 
 char k:4;
 unsigned long m; 
 //char k:4; 
 //unsigned short i:8;
 unsigned short j:8;
} ;
#pragma pack()
int main(){
	A b;
	cout<<sizeof(b)<<endl;
	system("pause");
	return 1;
}

 输出是9.

总结:位域将原类型占用的字节分成相应的位数,只有后面是相同的类型才能继续占用没有使用的位数;如果是不同的类型就需要按前面类型原有的字节来往后顺延到本类型开始的字节位置。

补充:

 

  指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16。

  #pragma pack规定的对齐长度,实际使用的规则是:

      结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的   数值和结构体的自然对齐长度中比较小的那个进行。就是说,当#pragma pack的值等于或超过所有数据成员长度的时     候,这个值的大小将不产生任何效果。 

实例:具体解释:

#pragma pack(4)

  class TestB

  {

  public:

    int aa; //第一个成员,放在[0,3]偏移的位置,

    char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。

    short b; //第三个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。

    char c; //第四个,自身长为1,放在[8]的位置。

  };

这个类实际占据的内存空间是9字节

类之间的对齐,是按照类内部最大的成员的长度,和#pragma pack规定的值之中较小的一个对齐的。

所以这个例子中,类之间对齐的长度是min(sizeof(int),4),也就是4。

9按照4字节圆整的结果是12,所以sizeof(TestB)是12。

 #pragma pack(2)

 

     class TestB

  {

  public:

    int aa; //第一个成员,放在[0,3]偏移的位置,

    char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。

    short b; //第三个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。

    char c; //第四个,自身长为1,放在[8]的位置。

  };

//可以看出,上面的位置完全没有变化,只是类之间改为按2字节对齐,9按2圆整的结果是10。

//所以 sizeof(TestB)是10。

#pragma pack(push) //保存对齐状态
#pragma pack(2)

struct A 
{ 
     char    b; 
     int      a; 
     short c; 
}; 
#pragma pack(pop) //恢复对齐状态

 int main()
{

    cout << sizeof(A)
 
分析:
这里指定了对齐长度为2;
b的对齐长度为1字节,存放地址:0x0000
a的对齐长度为2字节,存放地址:0x0002 ~ 0x0005;//数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
c的对齐长度为2字节,   存放地址:0x0006 ~ 0x0007;
A的对齐方式为2,(这里8是2的倍数,因此不用补0)
所以sizeof(A)为2的整数倍:8
 
分享到:
评论

相关推荐

    C语言结构体内存对齐问题.pdf

    结构体的使用提高了程序对数据的组织能力,但随之而来的内存对齐问题,是一个影响性能和内存使用的细节问题。下面我们详细讨论结构体内存对齐的概念、原因以及如何影响结构体的总大小。 1. 内存对齐的基本概念 在...

    内存对齐问题的完美解释.pdf

    内存对齐问题通常与编程语言中的数据类型、结构体布局和编译器特性紧密相关。在C语言中,`sizeof`操作符是理解内存对齐的关键工具。 `sizeof`的概念是获取一个类型或变量在内存中占用的字节数。它不是一个函数,...

    计算机编程时使用到的内存对齐问题解答

    通过深入理解内存对齐的概念和原理,开发者可以在编写高效代码的同时,避免因对齐问题引发的潜在问题。附带的PPT和示例程序将帮助你更直观地理解内存对齐的具体应用和实践,通过实际操作来巩固理论知识,提升编程...

    内存对齐问题的完美解释.docx

    内存对齐问题的完美解释 在本文中,我们将深入探讨 C 语言中的 sizeof 操作符,解释其概念、使用方法、结果类型、与其他操作符的关系及其主要用途,并以实际示例来展示 sizeof 的应用。 一、sizeof 概念 sizeof ...

    C语言结构体内存对齐问题浅析.pdf

    C语言结构体内存对齐问题浅析

    内存对齐 详细介绍内存对齐的原理

    虽然大多数情况下编译器会自动处理内存对齐问题,但在某些特殊场景下,开发者可能需要手动控制内存对齐。例如,在某些高性能计算领域,精确控制内存布局对于提高性能至关重要。 **使用`#pragma pack`控制对齐**: ...

    结构体大小-详解内存对齐问题

    从结构体内变量所占空间大小,默认内存对齐大小,强制内存对齐方法,变量在内存中布局的详细分析,语言言简意赅,绝无废话,为读者解决了大量寻找书籍的烦恼,读者可以花费几分钟的时间解决掉结构体内存对齐的所有问题,...

    内存对齐问题的完美解释.doc

    内存对齐是计算机科学中关于数据存储的一种策略,它的目的是优化数据访问速度并节省内存空间。在C语言中,`sizeof`操作符用于获取数据类型或变量所占用的内存大小。在描述的文档中,主要讨论了内存对齐在结构体`...

    内存对齐的问题 内存对齐内存对齐

    内存对齐,值得一读的内容, 内存对齐,值得一读的内容, 内存对齐,值得一读的内容, 内存对齐,值得一读的内容,

    如何理解 struct 的内存对齐? - 知乎1

    - `alignof`运算符可以查询类型或变量的对齐要求,这对于理解和调试内存对齐问题很有帮助。 7. **结构体嵌套和数组的影响**: - 当结构体包含其他结构体作为成员时,子结构体会按照自己的对齐规则对齐,这可能...

    C语言内存对齐.pdf

    - **跨平台编程**:不同的硬件平台可能有不同的对齐要求,因此在编写跨平台代码时需要考虑内存对齐问题。 - **高效数据传输**:在处理大量数据或进行网络传输时,对齐可以减少数据拷贝和转换的时间。 6. 解决对齐...

    商业编程-源码-关于内存对齐.zip

    这个压缩包很可能包含了一些示例代码,展示了如何在实际编程中处理内存对齐问题,包括如何创建对齐的数据结构、如何调整编译器设置以及如何处理跨平台兼容性。通过学习这些源代码,开发者可以更好地理解和掌握内存...

    结构内存对齐StructMemory 配图示

    在提供的代码文件中,`structMemory.cpp`很可能是实现和展示结构体内存对齐问题的示例。它可能包含了不同结构体定义,通过比较它们的`sizeof`结果来揭示对齐规则的影响。其他如`StdAfx.cpp`、`StdAfx.h`等文件是...

    C语言、C++内存对齐问题详解

    本文将深入解析C语言和C++中的内存对齐问题。 首先,内存对齐的主要目的是提高程序执行的效率。计算机的处理器在处理数据时,通常会一次性读取或写入多个字节的数据,例如,32位处理器可能一次处理4个字节。如果...

    C语言之struct大小、首地址与内存对齐[借鉴].pdf

    本文将详细地介绍C语言中struct的大小、首地址和内存对齐问题,以及不同的编译器和微处理器平台对struct的处理方式。 首先,对于处理器,大尾端、小尾端的因素必须考虑。在ANSI C标准中,并没有规定相邻声明的变量...

    5分钟搞定内存字节对齐

    这个大小是经过内存对齐调整后的结果。那么,为什么需要内存对齐呢?内存对齐是为了提高程序的执行效率和可移植性。在不同的体系结构中,CPU 对不同类型的数据的处理速度是不同的。为了提高程序的执行效率,编译器会...

    C语言内存对齐,提高寻址效率

    C语言内存对齐的重要性 C语言内存对齐是指在编译器中对变量或结构体成员的存储地址进行调整,以提高寻址效率和存取效率。这是因为CPU在访问内存时,并不是可以访问任意编号的字节,而是以一定的步长来访问内存的。...

    sizeof(结构体)和内存对齐

    sizeof(结构体)和内存对齐 sizeof(结构体)和内存对齐是C语言中一个重要的概念,它们之间存在着紧密的联系。sizeof(结构体)是指结构体在内存中的大小,而内存对齐是指编译器为了提高程序的效率和可移植性,对内存...

    编程语言的内存对齐

    内存对齐问题,主要介绍了C语言结构体重内存对齐的问题。

    深入理解c/c++ 内存对齐

    内存对齐,memory alignment.为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器...一般情况下不需要理会内存对齐问题,内存对齐是编译器的事情.但碰到一

Global site tag (gtag.js) - Google Analytics