c/c++ 内存对齐
来源:互联网 发布:天刀萌妹子捏脸数据 编辑:程序博客网 时间:2024/05/16 07:39
内存对齐,memory alignment.为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
内存对齐一般讲就是cpu access memory的效率(提高运行速度)和准确性(在一些条件下,如果没有对齐会导致数据不同步现象).依赖cpu,平台和编译器的不同.一些cpu要求较高(这句话说的不准确,但是确实依赖cpu的不同),而有些平台已经优化内存对齐问题,不同编译器的对齐模数不同.总的来说内存对齐属于编译器的问题.
一般情况下不需要理会内存对齐问题,内存对齐是编译器的事情.但碰到一些问题上还是需要理解这个概念.毕竟c/c++值直接操作内存的语言.需要理解程序在内存中的分布和运行原理.
总之一句话就是:不要让代码依赖内存对齐.
详细帖子见http://bbs.csdn.net/topics/30388330
1.原因:为什么需要内存对齐.
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
2.内存对齐的规则和范例
成员的内存分配规律:从结构体的首地址开始向后依次为每个成员寻找第一个满足条件的首地址x,该条件是x % N = 0,并且整个结构的长度必须为各个成员所使用的对齐参数中最大的那个值的最小整数倍,不够就补空字节。
结构体中所有成员的对齐参数N的最大值称为结构体的对齐参数。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐.主要体现在,最后一个元素对齐后,后面是否填补空字节,如果填补,填补多少.对齐将按照#pragma pack指定的数值(或默认值)和结构(或联合)最大数据成员类型长度中,比较小的那个进行。
3、结合1、2颗推断:当#pragma pack的n值等于或超过所有数据成员类型长度的时候,这个n值的大小将不产生任何效果。
VC++6.0中n 默认是8个字节,可以修改这个设定的对齐参数
也可以采用指令:#pragma pack(xx)控制.
1.基础例子
#pragma pack(n)struct A{char c; //1bytedouble d; //8byteshort s; //2byteint i; //4byte};int main(int argc, char* argv[]){A strua;printf("%len:d\n",sizeof(A));printf("%d,%d,%d,%d",&strua.c,&strua.d,&strua.s,&strua.i);return 0;}
1)n设置为8byte时
结果:len:24,
1245032,1245040,1245048,1245052
内存中成员分布如下:
strua.c分配在一个起始于8的整数倍的地址1245032(为什么是这样读者先自己思考,读完就会明白),接下来要在strua.c之后分配strua.d,由于double为8字节,取N=min(8,8),8字节来对齐,所以从strua.c向后找第一个能被8整除的地址,所以取1245032+8得1245040, strua.s 为2byte小于参数n,所以N=min(2,8),即N=2,取2字节长度对齐,所以要从strua.d后面寻找第一个能被2整除的地址来存储strua.s,由于strua.d后面的地址为1245048可以被2整除,所以strua.s紧接着分配,现在来分配strua.i,int为4byte,小于指定对齐参数8byte,所以N=min(4,8)取N=4byte对齐,strua.s后面第一个能被4整除地址为1245048+4,所以在1245048+4的位置分配了strua.i,中间补空,同时由于所有成员的N值的最大值为8,所以整个结构长度为8byte的最小整数倍,即取24byte其余均补0.
于是该结构体的对齐参数就是8byte。
2)当对齐参数n设置为16byte时,结果同上,不再分析
3)当对齐参数设置为4byte时
上例结果为:Len:20
1245036,1245040,1245048,1245052
内存中成员分布如下:
Strua.c起始于一个4的整数倍的地址,接下来要在strua.c之后分配strua.d,由于strua.d长度为8byte,大于对齐参数4byte,所以N=min(8,4)取最小的4字节,所以向后找第一个能被4整除的地址来作为strua.d首地址,故取1245036+4,接着要在strua.d后分配strua.s,strua.s长度为2byte小于4byte,取N=min(2,4)2byte对齐,由于strua.d后的地址为1245048可以被2
整除,所以直接在strua.d后面分配,strua.i的长度为4byte,所以取N=min(4,4)4byte对齐,所以从strua.s向后找第一个能被4整除的位置即1245048+4来分配和strua.i,同时N的最大值为4byte,所以整个结构的长度为4byte的最小整数倍20byte
4)当对齐参数设置为2byte时
上例结果为:Len:16
1245040,1245042,1245050,1245052
Strua.c分配后,向后找一第一个能被2整除的位置来存放strua.d,依次类推
5)1byte对齐时:
上例结果为:Len:15
1245040,1245041,1245049,1245051
此时,N=min(sizeof(成员),1),取N=1,由于1可以整除任何整数,所以各个成员依次分配,没有间空.
6)当结构体成员为数组时,并不是将整个数组当成一个成员来对待,而是将数组的每个元素当一个成员来分配,其他分配规则不变,如将上例的结构体改为:
struct A
{
char c; //1byte
double d; //8byte
short s; //2byte
char szBuf[5];
};
对齐参数设置为8byte,则,运行结果如下:
Len:24
1245032,1245040,1245048,1245050
Strua 的s分配后,接下来分配Strua 的数组szBuf[5],这里要单独分配它的每个元素,由于是char类型,所以N=min(1,8),取N=1,所以数组szBuf[5]的元素依次分配没有间隙。
看完上述的例子,基本分配的规律和方法应该已经知道.下面主要说明数组,嵌套结构体,指针时的一些内存对齐问题.
最重要的是自己写程序证明.
#include <iostream>#include <cstdio>using namespace std;#pragma pack(8)struct Args{ char ch; double d; short st; char rs[9]; int i;} args;struct Argsa{ char ch; Args test; char jd[10]; int i;}arga;int main(){// cout <<sizeof(char)<<" "<<sizeof(double)<<" "<<sizeof(short)<<" "<<sizeof(int)<<endl;//cout<<sizeof(long)<<" "<<sizeof(long long)<<" "<<sizeof(float)<<endl;cout<<"Args:"<<sizeof(args)<<endl;cout<<""<<(unsigned long)&args.i-(unsigned long)&args.rs<<endl;cout<<"Argsa:"<<sizeof(arga)<<endl;cout<<"Argsa:"<<(unsigned long)&arga.i -(unsigned long)&arga.jd<<endl;cout<<"Argsa:"<<(unsigned long)&arga.jd-(unsigned long)&arga.test<<endl;return 0;}输出结果:
10
Argsa:56
Argsa:12
Argsa:32
#include <iostream>#include <cstdio>#pragma pack(4)using namespace std;struct Args{ int i; double d; char *p; char ch; int *pi;}args;int main(){ cout<<"args length:"<<sizeof(args)<<endl; cout<<(unsigned long)&args.ch-(unsigned long)&args.p<<endl; cout<<(unsigned long)&args.pi-(unsigned long)&args.ch<<endl; return 0;}
设置pack为4时:
8
4
8
8
3.不同编译器中内存对齐
4.什么时候需要进行内存对齐.
一般情况下都不需要对编译器进行的内存对齐规则进行修改,因为这样会降低程序的性能,除非在以下两种情况下:
(1)这个结构需要直接被写入文件;
(2)这个结构需通过网络传给其他程序;
5.不足之处.
位段问题.这个问题有点复杂
具体应用的案例.
http://blog.csdn.net/daliaojie/article/details/7516099
http://blog.csdn.net/mbh_1991/article/details/10241785
http://developer.51cto.com/art/201002/183652.htm
http://m.oschina.net/blog/167508?p=2
http://blog.csdn.net/acorld/article/details/9104579
http://blog.csdn.net/anonymalias/article/details/8743857
http://www.dewen.org/q/5835/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E8%BF%9B%E8%A1%8C%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%EF%BC%9F?sort=active
http://bbs.ednchina.com/BLOG_ARTICLE_92132.HTM
http://stackoverflow.com/questions/12881179/why-is-memory-alignment-required
http://stackoverflow.com/questions/381244/purpose-of-memory-alignment
http://blog.csdn.net/linuxblack125125/article/details/7849743
- 【C/C++】内存对齐
- C中的内存对齐
- C/C++内存对齐
- C/C++内存对齐
- c 内存对齐
- C/C++内存对齐
- C/C++内存对齐
- C/C++ 内存对齐
- C/C++ 内存对齐
- C内存对齐详解
- C语言 内存对齐
- c 内存对齐
- C/C++内存对齐
- C语言内存对齐
- C/C++内存对齐
- C/C++内存对齐
- C/C++内存对齐
- C中的内存对齐
- ame初始化
- Spring基于 Annotation 的简单介绍
- 简单的三层架构及思想,总结(适合简单框架搭建)
- Pthread锁机制
- 求助:adodc:至少一个参数没有被指定值!
- c/c++ 内存对齐
- Java改变图片的大小
- 网络基础
- iOS实现跑马灯效果
- (standard c libraries translation )getutent
- form.cs窗口无法编辑按钮
- 用白话文描述activity生命周期
- 怎么实现十字记录法?
- 别拿生命熬夜,你为什么要熬夜