内存中的数据对齐
以下是程序员面试宝典中的一些内容:
计算结构变量的大小就必须讨论数据对齐问题。为了使CPU存取速度最快(这同CPU去操作数有关,详细的介绍可以参考一些计算机原理方面的书),C++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这样做会浪费一些内存,但在理论上CPU速度快了。
数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍。
CPU的优化规则大致原则是这样的,对于n字节的元素(n=2,4,8,....),它的首地址能被n整除,才能获得最好的性能。设计编译器的时候可以遵循这个原则:对于每一个变量,可以从当前位置向后找到第一个满足这个条件的地址作为首地址。
例:以下代码为32位机器编译,数据是以4字节为对齐单位,这两个类的输出结果为什么不同?
class B
{
private:
bool m_bTemp;
int m_nTemp;
bool m_bTemp2;
};
class C
{
private:
int m_nTemp;
bool m_bTemp;
bool m_bTemp;
};
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
在访问内存时,如果地址按4字节对齐,则访问效率会高很多。这种现象的原因在于访问内存的硬件电路。一般情况下,地址总线总是按照
对齐后的地址来访问的。例如你想得到0x00000001开始的4字节内容,系统首先需要以0x00000000读取4字节,从中取得3字节,然后再用 0x00000004作为开始地址,获得下一个4字节,再从中得到第一个字节,两次组合出你想得到的内容。但是如果地址一开始就是对齐到0x00000000,则系统只要一次读写即可。
本题中,第一种类的数据对齐是下面的情况:
|bool|----|----|----|
|--------int--------|
|bool|----|----|----|
第二种类的数据对齐是下面的情况:
|--------int--------|
|bool|bool|----|----|
所以类的大小分别是3X4和2X4。
答案:B类输出12字节,C类输出8字节。
struct Node
{
long a1;
short a2;
};
class person
{ private:
long a1;
short a2;
};
cout << sizeof(long) << endl;//输出为4
cout << sizeof(int) << endl;//输出为4
cout << sizeof(short) << endl;//输出为2
Node t;
cout << sizeof(t) << endl;//输出为8
person per;
cout << sizeof(per) << endl;//输出为8
在默认情况下,为了方便对结构体内元素的访问和管理,当结构体内的元素的长度都小于处 理器的位数的时候,便以结构体里面最长的数据元素为对齐单元,也就是说,结构体的长度 一定是最长的数据元素的整数倍,如果结构体内存在长度大于处理器位数的元素,那么就以 处理器的位数为对齐单位,但是结构体内类型相同的联素元素将在连续的空间内,和数组一 样
class A
{
};
class A2
{
char d, e;
};
cout << sizeof(A) << endl;//输出为1
cout << sizeof(A2) << endl;//输出为2
注意:对于一个类而言,即便是它为空类,编译器仍然要给它分配一个空间,即使它什么也
没有 class A3 {
static int ch;
};
cout << sizeof(A3) << endl;//输出为1
因为静态变量是存放在全局数据区的,而sizeof计算栈中分配的大小,是不会计算在内的
class T1
{
};
class T2: public virtual T1
{
};
cout << sizeof(T1) << endl;//输出为1
cout << sizeof(T2) << endl;//输出为4
空类所占空间为1,单一继承的空类也为1,多重继承的空类空间还是1,但是虚继承涉及 到虚表(虚指针),所以sizeof(T2)的大小为4
对于一个空类而言,事实上它有一个隐晦的一字节,那是被编译器安插进去的一个char,这 使得这个class的两个对象得以在内存中配置独一无二的地址