(转) 从D3DXMATRIX和D3DXMATRIXA16来说对齐方式

来源:互联网 发布:淘宝商铺号可以更改吗 编辑:程序博客网 时间:2024/05/19 11:18

这篇文章把人都看晕了。

 

D3D本身定义了矩阵类型,最基本的是 D3DMATRIX:
typedef struct _D3DMATRIX {
union {
struct {
float        _11, _12, _13, _14;
float        _21, _22, _23, _24;
float        _31, _32, _33, _34;
float        _41, _42, _43, _44;

};
float m[4][4];
};
} D3DMATRIX;

然后D3DXMATRIX继承了D3DMATRIX,并扩展定义了矩阵的运算符

然后D3DXMATRIXA16 定义为:

typedef __declspec( align(16) )  D3DXMATRIXA16    D3DXMATRIXA16

所以,D3DXMATRIXA16和D3DXMATRIX的区别在于前者的内存起始地址总是16的整数倍;
而后者的内存起始地址为4的整数倍; 用D3DXMATRIXA16的好处是:引用官方的说明——
16-byte aligned matrix, when used by D3DX math functions, has been optimized for improved performance on Intel Pentium 4 processors.
When using vectors and quaternions with D3DX math functions, use _declspec(align(16)) to generate byte aligned vectors and quaternions, because they will perform significantly better.

注意D3DXMATRIXA16 和 D3DXMATRIX 的sizeof()都是64字节;

下面来谈谈 内存对齐 到底是怎么回事:
对于结构体

struct  MyStruct

double dda1;
char     dda;
int        type;
};
double的sizeof()是8,char是1, int 是4, 而然在VC中sizeof( MyStruct) 的大小 != (13)8+1+4, 而是为16;为什么呢?首先必须知道: 
1.默认情况下,各(简单类型的)成员的变量存放的起始地址相对结构体起始地址的偏移量必须为该类型所占字节数(可以理解为该类型的 字节边界数,见后面说明)的整数倍:
double类型的起始地址 必须为 8的倍数;
char类型的起始地址必须为1的倍数;
int类型的起始地址必须为4的倍数;
所以,dda1的起始(偏移)地址0,满足,dda的起始地址为8,满足, type的起始地址为9,不满足,所以要填充3位,之后type起始地址为12,满足,此时占有空间8+1+3+4
2.默认情况下,会保证结构体大小 为 结构体的字节边界数 的整数倍, 所谓字节边界数就是 该结构体中占用最大空间的类型所占用的字节数;
对于上面的例子,double类型的8字节是MyStruct的字节边界数,所以结构体大小必须是8的倍数,这里
8+1+3+4为16,满足;当改变结构体顺序后:
struct MyStruct2

char      dda;
double  dda1;
int        type;
};
此时结构体占有空间为1+7+8+4+4=24;其中7比特是第一条规则的填充,最后一个4比特是第二条规则的填充;

下面再看一个有趣的例子:
struct S1

char    a;
int       b;


struct  S2

char         c;
struct S1  d;
double     e;
};

问结构体S2的大小是多少呢? 
结构体S1的大小,由上面说的可以知道为8,其字节边界数为4;
在S2中有成员d,而d不是简单类型,而是结构体,它的默认对齐方式是 其字节边界数,这里为4;
所以,在S2中,为a分配1,然后填充3,为S1类型的d分配8(1+3+4),此事偏移地址为12,所以还要填充4到16,再为double的e分配8,共计24,是8的倍数;

所以,说去说来,主要就是3点,总结如下:
1结构体在内存中的首地址能被其中最宽基本类型成员的大小所整除;
2 各成员的在结构体内部的起始偏移地址为每个成员字节边界数的整数倍, 
3 结构体总大小为 max(字节边界数)的整数倍;


上面只是默认情况,我们可以通过两个命令来修改默认规则,他们是:
__declspec( align( n ) )  和 #pragma pack(n );


#pragma pack(n )用来改变默认的对齐系数,在VC里面默认为8,gcc里面默认为4;
下面来介绍 一个概念 —— 对齐系数
当对齐系数设置为n时, 变量的 字节边界数为  min(n, 本来的字节边界输);
举例:
#pragma pack(push)
#pragma pack( 4 )
struct MyStruct

char     dda;
double dda1;
int        type;
};
#pragma pack(pop)

这里变量x的记字节边界数 为 E(x):
如果没有pack(4),E(dda) = 1;E(dda1) = 8; E(type) = 4 ; E(MyStruct)= E(dda1)= 8;
所以分配大小 1+7+8+4+4 = 24;

加上pack(4)以后,E(dda) = 1; E (dda1) = 4, E(type) = 4; E(MyStruct ) = 4;
所以此时分配的内存大小为 1+3+8+4+0 = 16


__declspec(align(n)) 则规定了 字节边界数的最小值
__declspec(align(16)) struct STRB
{
float a;
};

没有__declspec(align(n)),STRB的大小为1;
加了__declspec(align(n)),STRB结构体的sizeof为16;
注 1__declspec(align(n))的作用对象是结构体,对基本类型不起作用;
2__declspec(align(n))的优先级比#pragma pack(n)的优先级高

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 磁盘c5坏了怎么办 一体机装xp蓝屏怎么办 虚拟机密码忘记了怎么办 vivoy66手机太卡怎么办 虚拟机装xp蓝屏怎么办 exagear玩起来卡怎么办 第五人格模拟器玩太卡怎么办 速腾油箱盖打不开怎么办 奥迪a6油箱盖打不开怎么办 苹果手提虚拟机黑屏怎么办 mac系统桌面变大怎么办 删除文件要权限怎么办 页面载入错误了怎么办 手机打不开excel表格怎么办 皇室战争闪退怎么办 苹果老是闪退怎么办 黑苹果开机黑屏怎么办 MAC磁盘删了怎么办 mac磁盘被锁定怎么办 bt5读不到网卡怎么办 笔记本电脑cpu温度过高怎么办 笔记本cpu温度过高怎么办 联想系统崩溃了怎么办 办公软件用不了怎么办 win10设置闪退怎么办 手机浏览器版本低怎么办 wps界面动不了怎么办 手机设置删了怎么办 苹果手机设置不见了怎么办 笔记本电脑键盘不好使怎么办 网咖怎么办临时卡 cydia添加雷锋源失败怎么办 电脑mac已锁定怎么办 苹果home键发热怎么办 苹果软件消失了怎么办 苹果键盘消失了怎么办 苹果图标消失了怎么办 超账户授权有误怎么办 华为账号码被盗怎么办 华为无法截屏怎么办 华为账号密码忘怎么办