内存中数据对齐
计算机中内存空间中各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是数据对齐。
- 访问数据的内存地址要满足一定的条件:能被这个数据的长度所整除。 例如,1字节数据已经是对齐的,2字节的数据的地址要被2整除,4字节的数据地址要被4整除。
- 数据对齐并不是操作系统的内存结构的一部分,而是C P U结构的一部分。当C P U访问正确对齐的数据时,它的运行效率最高。
- 字节对齐是在编译时决定的,一旦决定则不会改变,因此即使有对齐的因素,也不会出现一个结构在运行时尺寸发生变化。
sizeof 和strlen 的区别
- sizeof是关键字,strlen是函数。
cout << strlen("\0") << endl; //0
cout << sizeof('\0') << endl; //1,被当作字符来处理
cout << sizeof("\0") << endl; //2,被当作字符串来处理,默认添加'\0'作为结尾
char str[] = "0123456789";
cout << strlen(str) << endl; //10
cout << sizeof(str) << endl; //11
strlen
执行的计数器的工作,它从内存的某个位置开始扫描,直到碰到第一个字符串结束符’\0’
为止,然后返回计数器值。sizeof
是关键字,它以字节的形式给出了其操作数的存储大小,操作数可以是一个表达式或类型名,操作数的存储大小由操作数的类型决定。
sizeof
类型(自定义类型)、函数作为参数,strlen只
能char*
作为参数,而且必须是以‘\0’结尾。sizeof
以函数作为参数,例如int g()
,则sizeof(g())
的值等价于sizeof(int)
的值。sizeof
后如果是类型需要加括号,如果是变量则不需要加括号,这是因为sizeof
是操作符而不是函数。
int a;
cout << sizeof a << endl; //无需加括号,正确
cout << sizeof (int) << endl; //需要加括号
- 大部分编译程序的
sizeof
都是在编译的时候计算,而strlen
在运行期间计算。
char ch[6];
int num[sizeof(ch)]; //真确
int num1[strlen(ch)]; //错误
sizeof 基本数据类型
sizeof 结构体
结构体的sizeof
是所有成员对齐后长度相加,而union共用体的sizeof
是取最大的成员长度。
结构体按照最大成员长度对齐,占用内存是即最大成员的整数倍。
struct A1 {
int a;
char c;
A1();
~A1(){}
};
struct A2 {
double d;
float f;
int a;
char c;
A2();
~A2() {}
};
int main(int argc, char* argv[]) {
cout << sizeof(A1) << endl; //8
cout << sizeof(A2) << endl; //24
return 0;
}
sizeof 只计算栈中分配的大小
struct A1 {
int a;
char c;
static float c1; //BSS段,不属于栈区
A1();
~A1(){}
};
struct A2 {
int a;
char c;
float c1;
A2();
~A2(){}
};
int main(int argc, char* argv[]) {
cout << sizeof(A1) << endl; //8
cout << sizeof(A2) << endl; //12
return 0;
}
sizeof 指针和引用
指针进行sizeof操作得到的是指针本身(所指向的变量(对象)的地址)的大小。
struct A {
int a;
char c;
};
int main(int argc, char* argv[]) {
A a;
A &b = a;
cout << sizeof(b) << endl; //8
A *c = &a;
cout << sizeof(c) << endl; //4
return 0;
}
数组作为参数传递给函数时传的是指针而非数组,传递的是数组的首地址。
int g(char ch[])
{
return sizeof(ch);
}
int _tmain(int argc, _TCHAR* argv[])
{
char ch[6];
cout << sizeof(ch) << endl; // 6
cout << g(ch) << endl; //4
return 0;
}
sizeof 与 类
sizeof 之虚函数
虚函数是由虚函数表和虚表指针来动态绑定的,在计算sizeof
时,无论有多少个虚函数,其只计算sizeof
(虚表指针)=4(64位为8)。
class A1 {
int a;
char c;
static char c1; //BSS段,不属于栈区
A1();
~A1() {}
virtual void f1() {}
virtual void f2() {}
virtual void f3() {}
};
int main(int argc, char* argv[])
{
cout << sizeof(A1) << endl; //12
return 0;
}
sizeof 之继承
- 基类的sizeof结果只与基类有关。
- 因存在继承关系,所以派生类的sizeof结果需要加上基类的sizeof结果。
- 当基类和派生类均有虚函数时,只计算一次sizeof(虚表指针)。
class A1 {
int a;
char c;
static char c1; //BSS段,不属于栈区
A1();
~A1() {}
virtual void f1() {}
virtual void f2() {}
virtual void f3() {}
};
class A2 : public A1{
float f;
void f1(){}
void f2(){}
void f3(){}
virtual void g1(){}
virtual void g2(){}
};
int main(int argc, char* argv[])
{
cout << sizeof(A1) << endl; //12,class A1占用12Byte
cout << sizeof(A2) << endl; //16,需要加上class A1占用12Byte
getchar();
return 0;
}
sizeof 之空类
class A1 {
};
class A2 : public A1{
};
int main(int argc, char* argv[])
{
cout << sizeof(A1) << endl; //1
cout << sizeof(A2) << endl; //1
return 0;
}
sizeof 之成员函数
一个类中,虚函数本身、成员函数(包括静态与非静态)都是不占用类对象的存储空间的。
class A1 {
void f1();
virtual int f2();
static int f3();
};
int main(int argc, char* argv[])
{
cout << sizeof(A1) << endl; //4
return 0;
}
sizeof 之对象
class A1 {
public:
void f1();
static int f3();
private :
int a;
static int b;
char c;
};
int main(int argc, char* argv[])
{
A1 a1;
cout << sizeof(a1) << endl; //8
return 0;
}
sizeof 之虚继承
虚承继的情况:需要增加一个虚表指针,因而增加4byte
class A {
public:
int a;
};
class B : virtual public A
{
public:
int b;
};
class C : virtual public B {
};
int main()
{
cout << sizeof(A) << endl; //4
cout << sizeof(B) << endl; //12
cout << sizeof(C) << endl; //16
return 0;
}
sizeof 之多重继承
class A {
public:
int a;
};
class B : virtual public A {
};
class C : virtual public A {
};
class D : public B, public C{
};
int main()
{
cout << sizeof(A) << endl; //4
cout << sizeof(B) << endl; //8
cout << sizeof(C) << endl; //8
//这里需要注意要减去4,因为B和C同时继承A,只需要保存一个A的副本就好了,sizeof(D)=4(A的副本)+4(B的虚表)+4(C的虚表)=12
cout << sizeof(D) << endl; //12
return 0;
}
sizeof 虚继承虚函数
class A
{
public:
virtual void aa() { }
virtual void aa2() { }
private:
char ch[3];
};
class B : virtual public A
{
};
class C : virtual public A
{
public:
virtual void bb() { }
virtual void bb2() { }
};
int main(void)
{
cout << sizeof(A) << endl; // 8
cout << sizeof(B) << endl; // 12
cout << sizeof(C) << endl; // 16
return 0;
}