ps: 环境:vc6.0
class A{
public:
int a;
char b;
int c;
};
int main()
{
A a;
a.a = 0;
a.b = 0;
cout<<sizeof(a)<<endl;
return 0;
}
汇编代码如下:
466: A a;
467: a.a = 0;
00401578 mov dword ptr [ebp-0Ch],0
468: a.b = 0;
0040157F mov byte ptr [ebp-8],0
469: a.c = 0;
00401583 mov dword ptr [ebp-4],0
470: cout<<sizeof(a)<<endl;
0040158A push offset @ILT+195(std::endl) (004010c8)
0040158F push 0Ch
00401591 mov ecx,offset std::cout (0047be90)
00401596 call @ILT+250
(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
0040159B mov ecx,eax
0040159D call @ILT+475
(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
471: return 0;
004015A2 xor eax,eax
从中可以看出类定义中的12(0CH)个字节,一开始我还纳闷了,但随后想到结构体中
的一个“内存对齐”的策略,随后翻了下书中关于结构体和类的讲解-“结构体和类的
唯一区别在于,结构体和类具有不同的默认访问控制属性”,看完这句话我恍然大悟
,原来如此啊,哈哈。
再看一下代码
#include <iostream>
using namespace std;
class A{
public:
int a;
char b;
int c;
char d;
};
汇编如下:
467: A a;
468: a.a = 0;
00401578 mov dword ptr [ebp-10h],0
469: a.b = 0;
0040157F mov byte ptr [ebp-0Ch],0
470: a.c = 0;
00401583 mov dword ptr [ebp-8],0
471: a.d = 0;
0040158A mov byte ptr [ebp-4],0
472: cout<<sizeof(a)<<endl;
0040158E push offset @ILT+195(std::endl) (004010c8)
00401593 push 10h
00401595 mov ecx,offset std::cout (0047be90)
0040159A call @ILT+250
(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
0040159F mov ecx,eax
004015A1 call @ILT+475
(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
473: return 0;
其中可以看出分配了16个字节,再看下面修改后的:
#include <iostream>
using namespace std;
class A{
public:
int a;
char b;
char d;
int c;
};
汇编如下:
467: A a;
468: a.a = 0;
00401578 mov dword ptr [ebp-0Ch],0
469: a.b = 0;
0040157F mov byte ptr [ebp-8],0
470: a.c = 0;
00401583 mov dword ptr [ebp-4],0
471: a.d = 0;
0040158A mov byte ptr [ebp-7],0
472: cout<<sizeof(a)<<endl;
0040158E push offset @ILT+195(std::endl) (004010c8)
00401593 push 0Ch
00401595 mov ecx,offset std::cout (0047be90)
0040159A call @ILT+250
(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
0040159F mov ecx,eax
004015A1 call @ILT+475
(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
473: return 0;
其中是分配了12字节。首先要知道:c++的结构体(或类)中,它的内存分布是按照成
员变量的顺序从低到高(题中是a(4byte)->b(1byte)->d(1byte)->(2byte被填充了)
->c(4byte) 这样的顺序)。这里有个特殊的例子:
class A{
public:
int a;
char b;
char d;
int c;
virtual void dd(){};
};
int main()
{
A a;
a.a = 0;
a.b = 0;
a.d = 0;
a.c = 0;
cout<<sizeof(a)<<endl;
return 0;
}
汇编代码:
469: A a;
00401588 lea ecx,[ebp-10h]
0040158B call @ILT+375(A::A) (0040117c)
470:
471: a.a = 0;
00401590 mov dword ptr [ebp-0Ch],0
472: a.b = 0;
00401597 mov byte ptr [ebp-8],0
473: a.d = 0;
0040159B mov byte ptr [ebp-7],0
474: a.c = 0;
0040159F mov dword ptr [ebp-4],0
475:
476: cout<<sizeof(a)<<endl;
004015A6 push offset @ILT+195(std::endl) (004010c8)
004015AB push 10h
004015AD mov ecx,offset std::cout (0047be90)
004015B2 call @ILT+250
(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
004015B7 mov ecx,eax
004015B9 call @ILT+480
(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)
477: return 0;
004015BE xor eax,eax
478: }
多了一个虚函数后的类多了四个字节,并且这四个字节并不是在最后高的四字节而是在最低的四字节(正好和我们前面讲的“按顺序从低到高"相反),这是因为虚函数在类的开头(也就是最低的四字节)插入了一个vptr指针。
最后得出结论:在类中定义成员变量时,要注意他们的顺序,根据“内存对齐”原则来达到节约内存的目的。
---本人菜鸟一只,大牛们多多指点啊。^_^