字节对齐
来源:互联网 发布:淘宝拍卖翡翠手镯不错 编辑:程序博客网 时间:2024/06/06 15:40
在c++中字节对齐主要存在符合类型中:union,struct和class中
先介绍四个概念:
1)数据类型自身的对齐值:基本数据类型的自身对齐值,等于sizeof(基本数据类型)。
2)指定对齐值:#pragma pack (value)时的指定对齐值value。
3)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
4)数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小的那个值。
有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是 数据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整 数倍)
#pragma pack (value)来告诉编译器,使用我们指定的对齐值来取代缺省的。
如#pragma pack (1) /*指定按2字节对齐*/
#pragma pack () /*取消指定对齐,恢复缺省对齐*/
1 union
Union就是取整个成员中大的内存块作为整个共用体的内存大小
对齐方式为成员中对齐方式最大的成员的对齐方式, 对界取编译器对界方式与自身大小中较小的一个
测试程序如下:
#include <iostream>
#include <stdio.h>
using std::cout;
using std::endl;
union u1
{
double a;
int b;
};
union u2
{
char a[13];
int b;
};
union u3
{
char a[13];
char b;
};
#pragma pack(2)//对界方式2字节¨²
union u4
{
char a[13];
int b;
};
union u5
{
char a[13];
char b;
};
#pragma pack() //恢复默认对界方式
void main()
{
cout<<sizeof(u1)<<endl;
cout<<sizeof(u2)<<endl;
cout<<sizeof(u3)<<endl;
cout<<sizeof(u4)<<endl;
cout<<sizeof(u5)<<endl;
system("pause");
}
测试结果如下:
8
16
13
14
13
结论:由于默认是8字节对齐, 在u1 中a为8字节,很明显u1的大小就为8
在u2中由于int为4字节,char为1 个字节,所以min(8,max(4,1))=4,以4字节对齐,u2理论为13个字节,要以4字节对齐的话所以为16字节。同理 u3 :min(max(1,1),8)=1,sizeof(u3)=13, u4: min(max(1,4),2)=2,sizeof(u4)=14,u5: min(max(1,1),2)=1,sizeof(u5)=13.
2 struct/class:都是对整个成员所占内存大小的求和。大小仅和成员变量的类型有关还和定义的先后顺序有关
举个例子,一个结构体如下:
typedef struct T
{
char c; //本身长度1字节
__int64 d; //本身长度8字节
int e; //本身长度4字节
short f; //本身长度2字节
char g; //本身长度1字节
short h; //本身长度2字节
};
假设定义了一个结构体变量C,在内存中分配到了0x00的位置,显然:
对于成员C.c 无论如何,也是一次寄存器读入,所以先占一个字节。
对于成员C.d 是个64位的变量,如果紧跟着C.c存储,则读入寄存器至少需要3次,为了实现最少的2次读入,至少需要以4字节对齐;同时对于8字节的原始变量,为了在寻址单位上统一,则需要按8字节对齐,所以,应该分配到0x08-0xF的位置。
对于成员C.e 是个32位的变量,自然只需满足分配起始为整数个32位即可,所以分配至0x10-0x13。
对于成员C.f 是个16位的变量,直接分配在0x14-0x16上,这样,反正只需一次读入寄存器后加工,边界也与16位对齐。
对于成员C.g 是个8位的变量,本身也得一次读入寄存器后加工,同时对于1个字节的变量,存储在任何字节开始都是对齐,所以,分配到0x17的位置。
对于成员C.h 是个16位的变量,为了保证与16位边界对齐,所以,分配到0x18-0x1A的位置。
分配图如下(还不正确,耐心读下去):
结构体C的占用空间到h结束就可以了吗?我们找个示例:如果定义一个结构体数组 CA[2],按变量分配的原则,这2个结构体应该是在内存中连续存储的,分配应该如下图:
分析一下上图,明显可知,CA[1]的很多成员都不再对齐了,究其原因,是结构体的开始边界不对齐。
那结构体的开始偏移满足什么条件才可以使其成员全部对齐呢。想一想就明白了:很简单,保证结构体长度是原始成员最长分配的整数倍即可。
上述结构体应该按最长的.d成员对齐,即与8字节对齐,这样正确的分配图如下:
当然结构体T的长度:sizeof(T)==0x20;
再举个例子,看看在默认对齐规则下,各结构体成员的对齐规则:
typedef struct A
{
char c; //1个字节
int d; //4个字节,要与4字节对齐,所以分配至第4个字节处
short e; //2个字节, 上述两个成员过后,本身就是与2对齐的,所以之前无填充
}; //整个结构体,最长的成员为4个字节,需要总长度与4字节对齐,所以, sizeof(A)==12
typedef struct B
{
char c; //1个字节
__int64 d; //8个字节,位置要与8字节对齐,所以分配到第8个字节处
int e; //4个字节,成员d结束于15字节,紧跟的16字节对齐于4字节,所以分配到16-19
short f; //2个字节,成员e结束于19字节,紧跟的20字节对齐于2字节,所以分配到20-21
A g; //结构体长为12字节,最长成员为4字节,需按4字节对齐,所以前面跳过2个字节,
//到24-35字节处
char h; //1个字节,分配到36字节处
int i; //4个字节,要对齐4字节,跳过3字节,分配到40-43 字节
}; //整个结构体的最大分配成员为8字节,所以结构体后面加5字节填充,被到48字节。故:
//sizeof(B)==48;
具体的分配图如下:
上述全部测试代码如下:
#include "stdio.h"
typedef struct A
{
char c;
int d;
short e;
};
typedef struct B
{
char c;
__int64 d;
int e;
short f;
A g;
char h;
int i;
};
typedef struct C
{
char c;
__int64 d;
int e;
short f;
char g;
short h;
};
typedef struct D
{
char a;
short b;
char c;
};
int main()
{
B *b=new B;
void *s[32];
s[0]=b;
s[1]=&b->c;
s[2]=&b->d;
s[3]=&b->e;
s[4]=&b->f;
s[5]=&b->g;
s[6]=&b->h;
s[7]=&b->g.c;
s[8]=&b->g.d;
s[9]=&b->g.e;
s[10]=&b->i;
b->c= 0x11;
b->d= 0x2222222222222222;
b->e= 0x33333333;
b->f=0x4444;
b->g.c=0x50;
b->g.d=0x51515151;
b->g.e=0x5252;
b->h=0x66;
int i1=sizeof(A);
int i2=sizeof(B);
int i3=sizeof(C);
int i4=sizeof(D);
printf("i1:%d\ni2:%d\ni3:%d\ni4:%d\n",i1,i2,i3,i4);//12 48 32 6
}
运行时的内存情况如下图:
ps:部分材料来自网络,本人整理而得
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- 字节对齐
- Extjs-实用工具 桌面组件 Ext.Desktop
- 如何使用 Visual Studio .NET 创建安装程序包
- 张洋博客
- 管理日志:茫然的困惑
- vs2010添加竖线的插件
- 字节对齐
- rehl5 主机名变成bogon
- 基于Video4Linux的视频采集模块开发
- 无线供电
- 页面显示乱码问题
- ContentObserver去实现拒收短信或短信黑名单等功能
- 一个兼容的js底部弹出框示例
- POSIX多线程编程
- jquery 焦点轮转背景图片消失, css 在作怪!