C++类、结构、对象内存浅析(sizeof)(很重要)
来源:互联网 发布:大二java课程设计题目 编辑:程序博客网 时间:2024/06/05 18:18
转载 :http://blog.csdn.net/fanfank/article/details/12175585
最近面试多,出的题目很多都有如下形式,给定一个class或者struct的定义,例如这样:
- struct node {
- int a;
- char b;
- int c;
- char d;
- };
问题是:sizeof(node) = ?
之前了解过对齐的概念,但是不深入,所以在这里自己做了一些小测试,说一下自己的看法。先告诉大家吧,上面那题答案是16。
如果用“对齐”的说法,那么就是先找到这个struct中占内存最大的一个类型——“int”,然后简单地进行“变量个数 * sizeof(int) = 4 * 4 = 16”即可。但是这样的做法其实有点问题,下面会继续探讨。
先上一段代码(可以自己先想一下这段代码的输出是什么?):
- #include<iostream>
- #include<stdio.h>
- using namespace std;
- struct node {
- int a;
- char b;
- int c;
- char d;
- node(){a=1,b=2,c=3,d=4;}
- };
- int main()
- {
- node n;
- printf("a:%d b:%d c:%d d:%d\n", n.a, n.b, n.c, n.d);
- void *p = &n;
- *((int*)p) = 12345;
- cout<<n.a<<endl;
- p = ((int*)p) + 1;
- *((char*)p) = 107;
- cout<<(int)n.b<<endl;
- p = ((char*)p) + 1;
- *((int*)p) = 0x80000000;
- cout<<(unsigned int)n.c<<endl;
- cout<<(int)n.d<<endl;
- cout<<"size:"<<sizeof(node)<<endl;
- int stop;
- cin>>stop;
- }
代码输出:
- a:1 b:2 c:3 d:4
- 12345
- 107
- 128
- 4
- size:16
解析如下(以下所有分析仅为本人推测所得,实际是否如此请参见更权威的资料):
void *p = &n这句,使得p指针指向了n的起始地址,然后我们将void*类型的指针转换为int*类型,并对其赋值12345,然后发现a变成了12345,说明a的首地址和n的首地址是相同的。
接着我们让指针p移动一个int的距离,向高地址方向移动,如果猜测没错,现在应该移动到了b的首地址,那么赋值操作将会使b的值变为107,输出也验证了这个猜测。
接下来就是重点了,我们让p移动一个char大小的距离(即1个字节),如果struct内的成员变量是密集排布的,那么现在应该移动到了c的位置,赋值0x80000000,换成二进制就是1000 0000 0000 0000 0000 0000 0000 0000,即便int的最小值-2147483648。然后输出c的值时发现其等于128。
什么时候int的值是128?只有其二进制为0000 0000 0000 0000 0000 0000 1000 0000的时候。红色字的部分就是被改变的部分,也就是说只有低地址的一个字节(8bit)被赋值了,另外的24bit内容丢失了吗?结合之前所说的“对齐”问题,那么就可以大胆猜测其实b和c之间隔了3个字节,所以进行赋值的时候,低位的24个bit作用在变量b后面的3个字节中,而高位的1000 0000作用在变量c的低位第一个字节上。
如果用一张图去形象地描述就如下:
其中一个方格(不是很方……)代表一个字节,红色的部分是a占用的内存空间,绿色是b,蓝色是c,黄色是d,而带斜线的部分则是被0x80000000赋值的内存区域。
好了,现在给出另外一个问题,如果struct是这样的:
- struct node {
- int a;
- char b;
- char d;
- int c;
- };
那么问sizeof(node) = ?
给个提示,现在的话,内存占用示意图会变成这样:
那么结果各位应该也知道了。好了,一些拓展问题,上面这个struct的内存是在栈中分配的,如果是用new运算符,使其在堆上面分配,那么结果是什么?各位可以亲手试一下,直接把答案全部说出来,就有点没有意思了,哈哈
好啦,其实到这里,文章还没完,要再进一步讲一些
下面要讨论类,即class。
按照惯例,继续先上代码,请猜猜下面各个类其sizeof的返回值是什么:
- #include<iostream>
- #include<stdio.h>
- using namespace std;
- class TwoIntNoVirtual {
- int a;
- int b;
- void function() {
- cout<<"Hello"<<endl;
- }
- };
- class TwoIntOneVirtual {
- int a;
- int b;
- virtual void function() {
- }
- };
- class TwoIntTwoVirtual {
- int a;
- int b;
- virtual void function() {
- }
- virtual void function2() {
- }
- };
- class TwoIntOneVirtualDerived : public TwoIntOneVirtual {
- void function2() {
- }
- };
- class TwoIntTwoVirtualDerived : public TwoIntTwoVirtual {
- void function() {
- }
- void function2() {
- }
- };
- class OtherTest {
- char e,f,g,h,i,j,k;
- int a;
- int b;
- int c;
- long long d;
- virtual void function() {}
- virtual void function2() {}
- };
- int main()
- {
- cout<<"TwoIntNoVirtual: "<<sizeof(TwoIntNoVirtual)<<endl;
- cout<<"TwoIntOneVirtual: "<<sizeof(TwoIntOneVirtual)<<endl;
- cout<<"TwoIntTwoVirtual: "<<sizeof(TwoIntTwoVirtual)<<endl;
- cout<<"TwoIntOneVirtualDerived: "<<sizeof(TwoIntOneVirtualDerived)<<endl;
- cout<<"TwoIntTwoVirtualDerived: "<<sizeof(TwoIntTwoVirtualDerived)<<endl;
- cout<<"OtherTest: "<<sizeof(OtherTest)<<endl;
- cout<<"Long long: "<<sizeof(long long)<<endl;
- int stop;
- cin>>stop;
- }
其实从上面讲完struct,现在就是多加了两点:1 函数对size有什么影响? 2 虚函数对size有什么影响?
首先,对于32位的机器,指针的size是4个字节,其次虚函数有虚表的概念,神马是虚表?可以google一下,学C++一定要知道的基础知识啊。
这个程序的输出如下:
TwoIntNoVirtual: 8
TwoIntOneVirtual: 12
TwoIntTwoVirtual: 12
TwoIntOneVirtualDerived: 12
TwoIntTwoVirtualDerived: 12
OtherTest: 32
Long long: 8
成员变量对内存的占用和struct一样,普通的函数不会影响size,但是虚函数会使得size至少增加4,因为指向虚表的指针占用4个字节,然而要注意,1个虚函数或者n个虚函数对这个类取size是得到相同的结果(为什么?请参见拓展阅读1)。更多实验结果,各位要亲自动手试一试,最后再增加一个结论,注意以下两个struct(得到的size是相同的,都为16,感谢一楼指出原本的错误!):
- struct node1 {
- int a;
- char b, c, d, e;
- long long f;
- };
- struct node2 {
- int a;
- int b;
- long long c;
- };
但是,下面这个struct,得到的size和上面是不同的(结果为24):
- class node0 {
- int a;
- char b;
- short c;
- char d;
- long long f;
- };
虽然a,b,c,d加起来是8个字节的宽度,但是其中d会被拥到“下一行”,可以用以下这段程序检验(同时发现了你可以在类的外部访问这个类的private成员了,神奇的指针啊):
- #include<iostream>
- using namespace std;
- class node0 {
- int a;
- char b;
- short c;
- char d;
- long long f;
- public:
- node0(): a(1), b(5), c(10), d(15), f(20) {}
- };
- struct node1 {
- int a;
- char b;
- char c;
- char d;
- char e;
- long long f;
- };
- struct node2 {
- int a;
- int b;
- long long c;
- };
- int main()
- {
- cout<<sizeof(node0)<<endl;
- cout<<sizeof(node1)<<endl;
- cout<<sizeof(node2)<<endl;
- node0 n0;
- void *p = &n0;
- p = ((long long*)p) + 1;
- cout<<(int)(*((char*)p))<<endl;
- int stop;
- cin>>stop;
- }
输出结果是:
24
16
16
15
到底对齐要怎么对?经过查百度百科后(搜索“内存对齐”),发现其中有一条:结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节
这篇文章很多都是个人通过实验的猜想,各位务必亲测一下或者做进一步的研究,免得误导大家那就遗臭万年了!如果纰漏,欢迎指出,多谢!
相信上面的内容,对于我来说,应该能应付大部分sizeof题目,后来看了一些资料,发现有牛人已经对这个问题作过文,这里附上拓展阅读的链接:
拓展阅读1:C++虚函数表解释
拓展阅读2:C++对象的内存布局(上)
拓展阅读3:C++对象的内存布局(下)
******<转载说明>******
转载注明:诚实的偷包贼
原文地址:http://blog.csdn.net/fanfank/article/details/12175585
******<转载说明/>******
- C++类、结构、对象内存浅析(sizeof)(很重要)
- C++类、结构对象内存布局浅析
- C++类、结构对象内存布局浅析
- 内存对齐和sizeof(结构体)
- 结构体的内存分配(sizeof)
- sizeof浅析(一)——求结构体大小
- sizeof浅析(一)——求结构体大小
- sizeof浅析(一)——求结构体大小
- sizeof浅析(二)
- Delphi 类与对象内存结构浅析(上)
- Delphi 类与对象内存结构浅析(下)
- Delphi 类与对象内存结构浅析(附件1)
- Delphi 类与对象内存结构浅析(附件2)
- C++类对象内存结构(转)
- sizeof(结构体)
- 关于C中结构体的大小问题(sizeof)
- 类的内存布局-sizeof(类对象)
- 类的内存布局-sizeof(转)
- iOS 系统地图实现及定位
- 使用phonegap建立安卓webapp项目及其问题总结
- 嫌工资少,先来看看你值多少钱
- R语言数据储存与读取
- PHP学习笔记01:php中的单引号、双引号和转义字符
- C++类、结构、对象内存浅析(sizeof)(很重要)
- Android基础知识_Activity SingleTop模式示例
- 批处理文件启动windows服务
- 山寨技术下的网站图片服务器(NGINX)
- jpa2.0动态查询机制
- offsetwidth/clientwidth的区别
- poj 2229 2的次方个数dp
- linux proc/net/
- 加载txt文件中的数据到MySQL表中