/*
在最近的项目中,我们涉及到了“内存对齐”技术。对于大部分程序员来说,“内存对齐”对他们来说都应该是“透明的”。“内存 对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。但是C语言的一个特点就是太灵活
,太强大,它允许你干预“内存对齐”。如果你想了解更加底层的秘密,“内存对齐”对你就不应该再透明了。 一、内存对齐
的原因
内存对齐(3张) 大部分的参考资料都是如是说的: 1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任 意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 2、性能原因:数据结构(尤其是栈)应
该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问
。 二、对齐规则 每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令
#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。 规则: 1、数据成员对齐规则
:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指
定的数值和这个数据成员自身长度中,比较小的那个进行。 2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,
结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3、结合1、2可推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
Win32平台下的微软C编译器(cl.exe for 80×86)的对齐策略: 1) 结构体变量的首地址是其最长基本类型成员的整数倍;
备注:编译器在给结构体开辟空间时,首先找到结构体中最宽的基本数据类型,然后寻找内存地址能是该基本数据类型的整倍的位置
,作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐模数。 2) 结构体每个成员相对于结构体首地址
的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding); 备注:为结构
体的一个成员开辟空间之前,编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍,若是,则存放
本成员,反之,则在本成员和上一个成员之间填充一定的字节,以达到整数倍的要求,也就是将预开辟空间的首地址后移几个字节。
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节
(trailing padding)。 备注:结构体总大小是包括填充字节,最后一个成员满足上面两条以外,还必须满足第三条,否则就
必须在最后填充几个字节以达到本条要求。 4) 结构体内类型相同的连续元素将在连续的空间内,和数组一样。 5) 如果结
构体内存在长度大于处理器位数的元素,那么就以处理器的倍数为对齐单位;否则,如果结构体内的元素的长度都小于处理器的倍数
的时候,便以结构体里面最长的数据元素为对齐单位。
*/ #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #endif #ifndef SAFE_DELETE_ARRAY #define SAFE_DELETE_ARRAY(p) { if(p) { delete [] (p); (p)=NULL; } } #endif #pragma pack(1); // sizeof(t) = 13; struct tag_test { int a; char b; short c; char d[6]; tag_test() { a = 1; b = 'c'; c = 1; memset(d,'a',6); } }; template <class T>
void Swap(T &a, T &b) { T p ; p = a; a = b; b = p; } void Fun(char *str)
{ int n = sizeof(str);//4 int m = sizeof(str[0]);//1 cout<<n<<endl; cout<<m<<endl; } void main()
{ tag_test t; int n = sizeof(t); cout<<n<<endl; int a = 1; int b = 2; cout<<a<<" "<<b<<endl; Swap(a,b); cout<<a<<" "<<b<<endl; char *s = "abcde"; Fun(s); int j = sizeof(s);// 4 int u = strlen(s);//5 int d = sizeof(s[0]);//1 cout<<j<<endl; cout<<d<<endl; cout<<u<<endl; char r[10];
cout<<sizeof(r)<<endl;// 10
} 最近在练习使用函数模板,在func.h定义了一个函数
我把函数模板的具体实现放在了func.cpp里
在main.cpp里面包含func.h, 然后调用functionA(obj) 编译各个文件都没问题,最后link的时候居然报告 functionA<ObjectType>(ObjectType) 找不到。 是不是函数模板的实现(我现在放在func.cpp的部分)必须放在func.h里面不然这个函数模板根本就没有实例化?我自己感觉是这样,但是不确定是不是,还望指点,谢谢! struct tag_TPClipQualityInfo
{
TP_CLIP_QUALITY_TYPE eQualityType;
TP_CLIP_CLASS_TYPE eClipClass; TPClipVAFormat stuClipVAFormat; //包含所有视音频信息 long lSubIndex; UINT uQualityState; CString sDescription[TP_CLIP_FILE_MAX]; TP_CLIP_CLASS_TYPE eDBEClass; CArray< _tagQualityItem2 *,_tagQualityItem2 *&> aQualityItem[TP_CLIP_FILE_MAX];
CArray< _tagGroupItem2 * ,_tagGroupItem2 *&> aGroupItem; CArray< _tagQualityItem2 *,_tagQualityItem2 *&> aTemp; tag_TPClipQualityInfo()
{
eQualityType = TP_CLIP_QUALITY_HIGH;
eClipClass = 0; eDBEClass = 0; uQualityState = 0; lSubIndex = 0; stuClipVAFormat.Reset(); for(INT l = 0; l < TP_CLIP_FILE_MAX; l++) sDescription[l] = _T(""); }
~tag_TPClipQualityInfo()
{ ReleaseItem(FALSE); Reset(); } void ReleaseItem(BOOL bBegin)
{
for(INT l=0;l<aTemp.GetSize();l++)
{ if(aTemp[l] ->sDataFileName) delete [] aTemp[l] ->sDataFileName;aTemp[l] ->sDataFileName = NULL; if(aTemp[l] ->sDataFilePath) delete [] aTemp[l] ->sDataFilePath;aTemp[l] ->sDataFilePath = NULL; delete aTemp[l]; } aTemp.RemoveAll();
}
void ReleaseGroupItem()
{ for(INT k=0;k<aGroupItem.GetSize();k++) { delete aGroupItem[k]; } aGroupItem.RemoveAll(); }*m_paClipQualityInfo[TP_CLIP_QUALITY_MAX]; TCHAR sName[MAX_PATH];
stuTemplateData.sFileName = (LPTSTR)(LPCTSTR)sFileName;
|
|