关于类的大小,请先查看:
类和结构体的内存空间占有问题
简介
C++类是由结构体发展得来的,所以他们的成员变量(C语言的结构体只有成员变量)的内存分配机制是一样的。
高字节与低字节,高地址与低地址,大端模式与小端模式
一、高地址与低地址
内存地址对应成16进制,值大的是高地址,反之为低地址。
二、高字节与低字节
如int a=16777220,化为十六进制是0x01 00 00 04则04属于低字节,01属于高字节
三、大端模式与小端模式
大端模式:高字节存放在低地址
小端模式:高字节存放在高地址
四、存放顺序
- 一个整数类型内部
低地址存储低位,高地址存储高位。比如int a=1,则存储情况为0000(高地址) 0000 0000 0001(低地址) - 若干个局部变量(在栈中存储的)
先定义的高地址,后定义的低地址 - 类、结构体或数组的元素
先定义的低地址,后定义的高地址
一
union U {
char cp[2];
short sp;
};
int main(int argc, char *argv[])
{
U temp;
temp.cp[1] = 1;
temp.cp[0] = 3;
cout << temp.sp << endl;
return 0;
}
结果:
259 // 0x0103 小端模式
二
int main(int argc, char *argv[])
{
int a;
char b;
int c;
short d;
long int e = 1;
char *p;
cout << "int &a = " << (size_t)&a << endl;//结果1
cout << "char&b = " << (size_t)&b << endl;//结果2
cout << "int &c = " << (size_t)&c << endl;//结果3
cout << "short&d = " << (size_t)&d << endl;//结果4
cout << "long &e = " << (size_t)&e << endl;//结果5
cout << "char*&p = " << (size_t)&p << endl;//结果6
char temp[16]={0};
memcpy(temp, &p, 16);
cout << (size_t)p << endl;
for ( int i = 0; i < 16; i++) {
cout << (int)temp[i] << " ";
}
cout << endl;
return 0;
}
结果:
int &a = 140722993149544
char&b = 140722993149543
int &c = 140722993149536
short&d = 140722993149534
long &e = 140722993149520
char*&p = 140722993149512
4233981
-3 -102 64 0 0 0 0 0 1 0 0 0 0 0 0 0
分析:
可以看见,局部变量从高地址开始分配,到低地址。
结果1 > 结果2 > 结果3 > 结果4 > 结果5 > 结果6
结果1 - 结果2 = 140722993149544 - 140722993149543 = 1B
//一个char占一个字节的内存
结果3 + 4B = 140722993149540
//一个字节的变量必须对齐,填充三个字节
结果5 - 结果6 = 140722993149520 - 140722993149512 = 8B
/*
char *占4个字节,但是内存分配了8个字节;
我们把内存打印出来:
4233981
-3 -102 64 0 0 0 0 0 1 0 0 0 0 0 0 0
可以看见,指针后面自带了一个字节的空字符
*/
三
单个指针和数组名指针有一点不同,那就是
单个指针有一个存储空间,且自带'\0'
结束符(如上),它的存储内容和地址不一样的
char *p;
&p != p
数组名指针,它的指向的地址都是在数组首地址
char a[10];
&a == a;
四
关于数组声明后再内存中的分配问题,作者实验了很久,发现同样的代码,连续几次编译后得到的结果,都是不一样的。
尤其是当有int[]
数组时,甚至出现违背第二条内存分配原则,int[]
数组总是被分配在最低的地址处。
作者猜测,这应该和编译器优化挂钩的。
虚函数
有虚函数的类里,有一张虚函数表,这张表里是每个虚函数的函数指针。对,它的大小就是所有指针加起来的大小。
这些指针放在类实例地址的低地址,也就是类对象头部。
然后就是各个变量。
派生类
如上图,子类实例化后的结构。
他有多少个父类每个父类的大小加起来在加上自身就是sizeof的大小。
话句话说,对于子类,最开始的内存数据记录着父类对象的拷贝(包括父类虚函数表指针和成员变量)。 之后是子类自己的成员变量数据。