基本类型
类型 |
含义 | 字节数 | 最小值 | 最大值 |
sbyte(c#) |
有符号的8位整数 | 1 | -128 | 127 |
byte(c#) |
无符号的8位整数 | 1 | 0 | 255 |
short |
有符号的16位整数 | 2 | -32768 | 32767 |
ushort |
16位无符号整数 | 2 | 0 | 65535 |
int |
有符号32位整数 | 4 | -2147483648 | 2147483647 |
uint |
无符号32位整数 | 4 | 0 | 4294967295 |
long |
有符号64位整数 | 8(64位)/4(32位) | -9223372036854775808 | 9223372036854775807 |
ulong |
无符号64位整数 | 8 | 0 | 18446744073709551615 |
decimal(C#) | 128 位精确的十进制值,28-29 有效位数 | -7.9 x 10^28 | 7.9 x 10^28 | |
double | 64 位双精度浮点型 | 8 | 5.0 x 10^-324 | 1.7 x 10^308 |
float | 32 位单精度浮点型 | 4 | -3.4 x 10^38 | 3.4 x 10^38 |
char | 16 位 Unicode 字符 | 2(C#)/1(C++) | ||
bool | 布尔值 | 1 |
特殊类型
- string 占32个字节
- 指针在32位系统占4字节,在64位占8字节
内存对齐
在存储一个结构体或者类时CPU会进行内存对齐。
内存对齐的原则:按照顺序,把每个数据放在min(当前数据大小,系统对齐值)的整数倍上。系统对齐值在32位上默认为4,64位上默认为8.也可以自己重新定义。
下面为举例,假设系统为32位。
struct asd3{
char a;
char b;
short c;
int d;
};//8字节
struct asd4{
char a;
short b;
char c
int d;
};//12字节
asd3对齐过程:
a数据大小为1,放在第0位;
b数据大小为1,1是它的整数倍,放在第1位上;
c数据大小为2,2是它的整数倍,放在第2位上;
d数据大小为4,放在第4位上.
asd4对齐过程:
a数据大小为1,放在第0位;
b数据大小为2,1不是它的整数倍,2是它的整数倍,放在第2位上;
c数据大小为1,4是它的整数倍,放在第4位上;
d数据大小为4,5,6,7都不是它的整数倍,放在第8位上.
struct asd1{
char a;
int b;
short c;
double d;
};//20个字节
asd1对齐过程:
a数据大小为1,放在第0位;
b数据大小为4,1,2,3都不是它的整数倍,放在第4位上;
c数据大小为2,8是它的整数倍,放在第8位上;
d数据大小为8,大于系统对齐值4,10,11,都不是4的整数倍,放在第12位上.
内存对齐的意义在于:不浪费太多内存的情况下,尽可能提高数据访问读取的效率。
类的大小
首先,类的大小与普通数据成员、虚函数、继承关系有关,与普通成员函数,静态成员函数,静态数据成员,静态常量数据成员无关。
存在继承时,内存先加上基类的大小;存在虚函数时,先计算虚函数指针的大小,注意虚函数无论有几个都只算一个指针(包括基类的在内);最后是数据成员本身的大小。以上这些计算都遵循内存对齐的原则。
特殊地,空类本身占一个字节,若被继承时,算作0字节。
class A
{
};
class B
{
char ch;
virtual void func0() { }
};
class C
{
char ch1;
char ch2;
virtual void func() { }
virtual void func1() { }
};
class D: public A, public C
{
int d;
virtual void func() { }
virtual void func1() { }
};
class E: public B, public C
{
int e;
virtual void func0() { }
virtual void func1() { }
};
int main(void)
{
cout<<"A="<<sizeof(A)<<endl; //result=1
cout<<"B="<<sizeof(B)<<endl; //result=16
cout<<"C="<<sizeof(C)<<endl; //result=16
cout<<"D="<<sizeof(D)<<endl; //result=24
cout<<"E="<<sizeof(E)<<endl; //result=40
return 0;
}
1.A为空类,所以大小为1
2.B的大小为char数据成员大小+vptr指针大小。由于字节对齐,大小为8+8=16
3.C的大小为两个char数据成员大小+vptr指针大小。由于字节对齐,大小为8+8=16
4.D为多继承派生类,由于D有数据成员,所以继承空类A时,空类A的大小1字节并没有计入当中,D继承C,此情况D只需要一个vptr指针,所以大小为数据成员加一个指针大小。由于字节对齐,大小为16+8=24
5.E为多继承派生类,含虚函数覆盖的情况。此时大小计算为基类大小加本地数据。考虑字节对齐,结果为16+16+8=40