关于sizeof类大小的奇怪问题,求大神求解!

jqdy 2014-10-22 04:38:19
//t.cpp
#include "stdafx.h"
#include<iostream>
#include<functional>
using namespace std;
class A{
virtual void foo(){}
};
class B{
double i;
char j;
virtual void foo(){}
};
int _tmain(int argc, _TCHAR* argv[])
{
cout<<sizeof(A)<<endl;//4
cout<<sizeof(B)<<endl;//24?? WHY??
return 0;
}

结果是
4
24
这个4可以理解,是类A对于虚函数拥有一个指向虚表的指针。指针大小为4个字节。
这个B的sizeof居然是24?C++对于字节对齐不应该是8+(1+4)=16。为何是24?求解
...全文
336 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
mujiok2003 2014-10-23
  • 打赏
  • 举报
回复
引用 12 楼 mujiok2003 的回复:
msvc加上选项/d1reportAllClassLayout可以在编译时输出内存布局
class A size(8):
        +---
 0      | {vfptr}
        +---

A::$vftable@:
        | &A_meta
        |  0
 0      | &A::foo

A::foo this adjustor: 0


class B size(24):
        +---
 0      | {vfptr}
 8      | i
16      | j
        | <alignment member> (size=7)
        +---

B::$vftable@:
        | &B_meta
        |  0
 0      | &B::foo

B::foo this adjustor: 0
以上是x64编译的输出, x86编译应该略哟不同。
mujiok2003 2014-10-23
  • 打赏
  • 举报
回复
msvc加上选项/d1reportAllClassLayout可以在编译时输出内存布局
class A size(8):
        +---
 0      | {vfptr}
        +---

A::$vftable@:
        | &A_meta
        |  0
 0      | &A::foo

A::foo this adjustor: 0


class B size(24):
        +---
 0      | {vfptr}
 8      | i
16      | j
        | <alignment member> (size=7)
        +---

B::$vftable@:
        | &B_meta
        |  0
 0      | &B::foo

B::foo this adjustor: 0
帅气小小少 2014-10-23
  • 打赏
  • 举报
回复
楼主用的编译器是什么? VS,VC默认是8字节对齐。 gcc是4字节。 如果是VS,VC, 加上#pragma pack(4) 强制4字节对齐,看下结果。 你的理解是正确的,B的大小应该是16。
sg_knight 2014-10-23
  • 打赏
  • 举报
回复
引用 4 楼 u013696062 的回复:
[quote=引用 3 楼 sg_knight 的回复:] 估计是按double长度对齐了。
为何按double对齐,C++对齐里面没有这个说法吧。看2楼我的回复,也不可能这样吧。。。[/quote] http://www.cnblogs.com/graphics/archive/2010/08/12/1797953.html 这里有详细介绍。 Projects-Properties-Configuration Properties-C/C++-Code generation-Struct Member Alignment, 如果没有修改过,则默认值是Default,即8字节对齐。 如果改成4字节对齐,则是16
mujiok2003 2014-10-23
  • 打赏
  • 举报
回复
引用 14 楼 u013696062 的回复:
[quote=引用 13 楼 mujiok2003 的回复:] [quote=引用 12 楼 mujiok2003 的回复:] msvc加上选项/d1reportAllClassLayout可以在编译时输出内存布局
class A size(8):
        +---
 0      | {vfptr}
        +---

A::$vftable@:
        | &A_meta
        |  0
 0      | &A::foo

A::foo this adjustor: 0


class B size(24):
        +---
 0      | {vfptr}
 8      | i
16      | j
        | <alignment member> (size=7)
        +---

B::$vftable@:
        | &B_meta
        |  0
 0      | &B::foo

B::foo this adjustor: 0
以上是x64编译的输出, x86编译应该略哟不同。 [/quote] 多谢提供这个方法。但是还是有问题:
class A{
	virtual void foo(){}
};
class B{
	char j;
	double i;
	virtual void foo(){}
};
int _tmain(int argc, _TCHAR* argv[])
{
	cout<<sizeof(A)<<endl;//4
	cout<<sizeof(B)<<endl;//24?? WHY??
	return 0;
}
在32bit下编译,B的结果还是24.查看内存分布: 1> class A size(4): 1> +--- 1> 0 | {vfptr} 1> +--- 1> 1> A::$vftable@: 1> | &A_meta 1> | 0 1> 0 | &A::foo 1> 1> A::foo this adjustor: 0 1> 1> 1> class B size(24): 1> +--- 1> 0 | {vfptr} 1> 8 | j 1> | <alignment member> (size=7) 1> 16 | i 1> +--- 这个有点郁闷了,j为何要在8字节,命名第4字节可用啊。 但是如果加上#pragma pack(4) 。输出的就是sizeof(B)=16了。好吧,可能认为VS中字节对齐方式不固定。[/quote] 64位系统, 地址也是64为呀。
jqdy 2014-10-23
  • 打赏
  • 举报
回复
结题了。。。。
jqdy 2014-10-23
  • 打赏
  • 举报
回复
引用 13 楼 mujiok2003 的回复:
[quote=引用 12 楼 mujiok2003 的回复:] msvc加上选项/d1reportAllClassLayout可以在编译时输出内存布局
class A size(8):
        +---
 0      | {vfptr}
        +---

A::$vftable@:
        | &A_meta
        |  0
 0      | &A::foo

A::foo this adjustor: 0


class B size(24):
        +---
 0      | {vfptr}
 8      | i
16      | j
        | <alignment member> (size=7)
        +---

B::$vftable@:
        | &B_meta
        |  0
 0      | &B::foo

B::foo this adjustor: 0
以上是x64编译的输出, x86编译应该略哟不同。 [/quote] 多谢提供这个方法。但是还是有问题:
class A{
	virtual void foo(){}
};
class B{
	char j;
	double i;
	virtual void foo(){}
};
int _tmain(int argc, _TCHAR* argv[])
{
	cout<<sizeof(A)<<endl;//4
	cout<<sizeof(B)<<endl;//24?? WHY??
	return 0;
}
在32bit下编译,B的结果还是24.查看内存分布: 1> class A size(4): 1> +--- 1> 0 | {vfptr} 1> +--- 1> 1> A::$vftable@: 1> | &A_meta 1> | 0 1> 0 | &A::foo 1> 1> A::foo this adjustor: 0 1> 1> 1> class B size(24): 1> +--- 1> 0 | {vfptr} 1> 8 | j 1> | <alignment member> (size=7) 1> 16 | i 1> +--- 这个有点郁闷了,j为何要在8字节,命名第4字节可用啊。 但是如果加上#pragma pack(4) 。输出的就是sizeof(B)=16了。好吧,可能认为VS中字节对齐方式不固定。
jqdy 2014-10-22
  • 打赏
  • 举报
回复
引用 8 楼 lovesmiles 的回复:
[quote=引用 7 楼 u013696062 的回复:] [quote=引用 5 楼 lovesmiles 的回复:] 虚函数表指针一般默认是放在类的前面的,所以定义变量的顺序可能有影响。
不是吧。。。。
class C
{
	char i;
	double j;
	virtual void foo(){}
};
int _tmain(int argc, _TCHAR* argv[])
{
	cout<<sizeof(C)<<endl;//24??
	return 0;
}
还是24. 还有虚函数指针不是放在类的前面的。分配字节的时候,是按照虚函数定义的地方的顺序分配的。[/quote] class C { virtual void foo1(){} double j; virtual void foo2(){} }; 要你这么说,虚函数表指针在这个类里面应该放在哪里?为了实现多态,虚函数表指针的位置是固定的,不管有多少个虚函数,也不管在什么位置定义。[/quote] 嗯,有道理。这里是我错了。
勤奋的小游侠 2014-10-22
  • 打赏
  • 举报
回复
引用 7 楼 u013696062 的回复:
[quote=引用 5 楼 lovesmiles 的回复:] 虚函数表指针一般默认是放在类的前面的,所以定义变量的顺序可能有影响。
不是吧。。。。
class C
{
	char i;
	double j;
	virtual void foo(){}
};
int _tmain(int argc, _TCHAR* argv[])
{
	cout<<sizeof(C)<<endl;//24??
	return 0;
}
还是24. 还有虚函数指针不是放在类的前面的。分配字节的时候,是按照虚函数定义的地方的顺序分配的。[/quote] class C { virtual void foo1(){} double j; virtual void foo2(){} }; 要你这么说,虚函数表指针在这个类里面应该放在哪里?为了实现多态,虚函数表指针的位置是固定的,不管有多少个虚函数,也不管在什么位置定义。
jqdy 2014-10-22
  • 打赏
  • 举报
回复
引用 5 楼 lovesmiles 的回复:
虚函数表指针一般默认是放在类的前面的,所以定义变量的顺序可能有影响。
不是吧。。。。
class C
{
	char i;
	double j;
	virtual void foo(){}
};
int _tmain(int argc, _TCHAR* argv[])
{
	cout<<sizeof(C)<<endl;//24??
	return 0;
}
还是24. 还有虚函数指针不是放在类的前面的。分配字节的时候,是按照虚函数定义的地方的顺序分配的。
勤奋的小游侠 2014-10-22
  • 打赏
  • 举报
回复
在代码前面加上#pragma pack(1) 确实是16字节,变成了24字节确实是内存对齐产生的。至于为什么是这样,那就得确定一下vc的内存布局了。
勤奋的小游侠 2014-10-22
  • 打赏
  • 举报
回复
虚函数表指针一般默认是放在类的前面的,所以定义变量的顺序可能有影响。
jqdy 2014-10-22
  • 打赏
  • 举报
回复
引用 3 楼 sg_knight 的回复:
估计是按double长度对齐了。
为何按double对齐,C++对齐里面没有这个说法吧。看2楼我的回复,也不可能这样吧。。。
sg_knight 2014-10-22
  • 打赏
  • 举报
回复
估计是按double长度对齐了。
jqdy 2014-10-22
  • 打赏
  • 举报
回复
引用 1 楼 xpdavis 的回复:
貌似按照最大的那个域double做对齐的,这样三个域都是8字节
这个。。。不是这样的吧。
class B{
	double i;
	char j;
	int k;
};
int _tmain(int argc, _TCHAR* argv[])
{
	cout<<sizeof(B)<<endl;//16
	return 0;
}
这个结果为何是16呢?
铖邑 2014-10-22
  • 打赏
  • 举报
回复
貌似按照最大的那个域double做对齐的,这样三个域都是8字节

64,648

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧