char:1个字节
wchar_t:2个字节
bool:1个字节
short:2个字节
int:4个字节
float:4个字节
double:8个字节
long long:8个字节
32位系统:
long:4个字节
指针:4个字节
64位系统:
long:8个字节
指针:8个字节
unsigned不影响sizeof的取值。
对函数使用sizeof,再编译阶段会被函数返回值的类型取代,如int f1()会返回4,double f2()会返回8.
数组大小就是各维数的乘积*数组元素的大小。
char a[] = "abcdef";
int b[20] = {3, 4};
char c[2][3] = {"aa", "bb"};
cout<
数组a的大小在定义时未指出,编译时分配给它的空间按照初始化的值确定,未元素个数加1,为7;
b为分配的20个元素*4=80;
c为2*3=6
看这一段程序:
int *d = new int[10];
cout << sizeof(d) << endl;
d是动态数组,它实质上是一个指针,所以sizeof(d)的值为4.
对齐:
现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐
为什么需要内存对齐?
1.不同硬件平台不一定支持访问任意内存地址数据,使用内存对齐可以保证每次访问都从块内存地址头部开始存取
2.提高cpu内存访问速度,内存是分块的,如两字节一块,四字节一块,考虑这种情况:一个四字节变量存在一个四字节地址的后三位和下一个四字节地址的前一位,这样cpu从内存中取数据便需要访问两个内存并将他们组合起来,降低cpu性能
用空间换时间
能否用memcmp对两个结构体内存进行比较?
不可以,memcmp是逐个字节对比的,但当字节对齐时,中间的填充部分是随机的,不确定的地址,所以比较的结果是不正确的。
结构体字节对齐的细节和具体编译器实现相关,但一般而言满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节{trailing padding}。
例1:
结构体定义如下:
struct A
{
char a;
short b;
int c;
};
a占用一个字节之后,为使b满足2要求,需要再a之后填充一个字节。总的占用为8字节内存。
例2:
结构体定义如下:
struct A
{
short b;
int c;
char a;
};
为了使c满足第二条准则,需要在给b填充两个字节之后再次填充两个字节。同时为了满足第三条准则,需要在给a填充一个字节之后再在后方填充三个字节。总占用内存为12个字节。
例3:
结构体定义如下:
typedef struct
{
char a;
short b;
char c;
int d;
char e[3];
}T_Test;
sizeof(T_Test)为16;
char a占用1个字节,
short b占用2个字节,在a与b之间填充1个字节
char c占用1个字节
int d占用4个字节,在c与d之间填充3个字节
char e[3]占用3个字节,之后补充1个字节,
sizeof(T_Test)共16个字节。
例4:
有指定时其对齐的规则是:每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里是8字节)中较小的一个对齐,并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。
程序如下:
#pragma pack(2) //指定按2字节对齐
struct C
{
char b;
int a;
short c;
};
#pragma pack() //取消指定对齐,恢复缺省对齐
分析:
b占用1个字节
a占用4个字节,大于2,分成两个2字节,在b与a之间填充1个字节,c占用2个字节,一共8个字节。
sizeof(struct C) = 8.
添加一个后来看到的结构体里嵌套结构体的sizeof大小求解问题:
struct stu
{
int i;
struct
{
char c;
int j;
}ss;
int k;
};
cout << sizeof(stu) << endl;
这段程序运行结果为16,求最大的类型占用空间时,将嵌套的struct结构体ss展开了,最大为int占用的4位,
但是内部嵌套的struct结构体在计算空间时不与外部元素相合并。所以总的大小为:4+4+4+4=16.
再看一个嵌套结构体的例子:
struct stu
{
char i;
struct
{
char c;
int j;
}ss;
char a;
char b;
char d;
char e;
char f;
};
cout << sizeof(stu) << endl;
这段程序运行的结果为20,最大为int占4位,第一个char i占4位,ss内char c占4位,int j占4位,
a,b,d,e占4位,f占4位,一共占20位没毛病。
再看一个嵌套数组的例子:
struct stu
{
float f;
char p;
int adf[3];
};
cout << sizeof(stu) << endl;
输出结果为20,同嵌套结构体一样,确定最大占用空间类型时将数组拆分开,而不是用整个数组占用空间大小作为标准,
所以最大为int或float的4位,4+4+4*3=20。
1.
sizeof空类大小为1.
2.
class A
{
public:
int a;
private:
char b;
};
cout << sizeof(A) << endl;
简单类和求结构体的sizeof一样,考虑偏移和对齐,结果为8.
3.带虚函数的类
class A
{
public:
int a;
virtual void f() {}
};
cout << sizeof(A) << endl;
虚函数放在虚表中,类中定义了虚函数,需要存放一个指向虚表的指针。
sizeof(A)=sizeof(A.a)+sizeof(指针)=4+4=8;(指针在32位系统为4位)。
当存在多个虚函数时,仍然只需要一个指向虚表的指针:
class A
{
public:
int a;
virtual void f() {}
virtual void f1() {}
virtual void f2() {}
};
cout << sizeof(A) << endl;
结果仍然为8.
4.继承的类
普通继承的空间计算结果是sizeof(基类)+sizeof(派生类)。对齐考虑的是所有类中占用空间最大的数据类型。
class A {
public:
int a;
char b;
};
class B:public A
{
char c;
};
cout << sizeof(B) << endl;
结果取决于编译器,vs中结果为12,说明将char b和char c是分开的,4+4+4=12.
class A
{
public:
int a;
};
class C :public A
{
public:
int c;
double e;
};
cout << sizeof(C) << endl;
但是到这里结果又变成了16了,这不就是将a和c合并在一个8的空间了吗?按照上一个例子,a和c应该各自占用8个空间呀……不是很懂,有点玄学……
class A {
public:
int a;
virtual void get() {}
};
class B:public A
{
public:
int c;
virtual void set() {}
};
cout << sizeof(B) << endl;
基类和继承类中均包含虚函数时,同样只存放于一个虚表中,因此只需要一个指针,所以结果是4+4+4=12.
多重继承的情况:
class A
{
public:
int a;
};
class B :public A
{
public:
int b;
};
class C :public A
{
public:
int c;
};
class D :public B, public C
{
public:
int d;
};
cout << sizeof(D) << endl;
sizeof(D)=sizeof(B)+sizeof(C)=(4+4)+(4+4)+4=20
union的sizeof:
union u
{
double a;
int b;
};
union u1
{
char a[13];
int b;
};
union u2
{
char a[13];
char b;
};
cout << sizeof(u) << endl;
cout << sizeof(u1) << endl;
cout << sizeof(u2) << endl;
结果为8,16,13.
解析:
union的大小取决于它所有的成员中,占用空间最大的一个成员的大小。
u中最大的成员就是double a,sizeof(u)=8.
u1中占用最大的是char[13],但是需要与int对齐,所以最大为16.
u2占用最大的是char[13],所以为13.
另外,static关键字不占用class的内存,所有对象共享一个内存。
部分参考于:点击打开链接
点击打开链接