有一个求类型所占几字节这个问题经常反复出现,这里我决定深入的研究一下
先简单入手
Sizeof(char) = 1;
Sizeof(bool) =1;
Sizeof(double)= 8;
Sizeof(float) =4;
Sizeof(int) =4;
基本类型就这些。这些是不能出错的。
深入一层:
大家都知道编译器会对它进行优化。
如果我们在win32默认情况下 在vs2005编译器。
默认情况下先说两个规程
1. 类型的大小是:类型包含的基本类型中最大的整数倍。如下: sizeof(A)的大小是最大基本类型 double(8)的整数倍。
2. 每个基本类型的偏移地址必须是类型大小的整数倍。例如 int的偏移量必须是 0,4,8,12,16,….. double 的偏移量必须是0,8,16,24,32.
一.class A {
int a;
bool b;
char c;
double d;
};
a | a | a | a |
b | c | 填充 | 填充 |
d | d | d | d |
D | d | d | d |
sizeof(A)=sizeof(int)+sizeof(bool)+sizeof(char)+2+sizeof(double = 16
二. class A {
char c;
double d;
int a;
bool b;
};
c | 填充 | 填充 | 填充 |
填充 | 填充 | 填充 | 填充 |
d | d | d | d |
d | d | d | d |
a | a | a | a |
b | 填充 | 填充 | 填充 |
sizeof(A)=sizeof(char)+7+sizeof(doulbe)+sizeof(int)+sizeof(bool)+ 3 = 24. 24是double 的整数倍。 所以24是最终结果。
再看一个例子:
三. Class A{
Chara;
Double b;
Int c;
};
a | 填充 | 填充 | 填充 |
填充 | 填充 | 填充 | 填充 |
b | b | b | b |
b | b | b | b |
c | c | c | c |
填充 | 填充 | 填充 | 填充 |
sizeof(A)=sizeof(char)+7+sizeof(doulbe)+sizeof(int) = 20 20不是double 的整数倍,所以还得填充4个。 所以24是最终结果。
我们再深入一下
四. class CA
{
char a;
double b;
int c;
};
这个我们好理解。 sizeof(CA)=sizeof(char)+7+sizeof(doulbe)+sizeof(int) + 4 = 24
class CB {
char ch;
CA ca;
int ib;
};
Sizeof(CB)的大小,就稍微有点麻烦了。在类成员为止的时候必须是类中最大的整数倍。 Sizeof(char)+ sizeof(CA)= 1+24 =25 不是CA当中最大类型的整数倍(最大是8)需要填充7个。所以 为 1+7+24 + sizeof(int) = 36。 36不是8的整数倍,又需要填充4个,所以最终结果是40.
Ch | 填充 | 填充 | 填充 |
填充 | 填充 | 填充 | 填充 |
Ca的部分 | Ca的部分 | Ca的部分 | Ca的部分 |
Ca的部分 | Ca的部分 | Ca的部分 | Ca的部分 |
Ca的部分 | Ca的部分 | Ca的部分 | Ca的部分 |
Ca的部分 | Ca的部分 | Ca的部分 | Ca的部分 |
Ca的部分 | Ca的部分 | Ca的部分 | Ca的部分 |
Ca的部分 | Ca的部分 | Ca的部分 | Ca的部分 |
ib | ib | ib | ib |
填充 | 填充 | 填充 | 填充 |
五.我们再深入一下
union u
{
double a;
int b;
};
union u2
{
char a[13];
int b;
};
union u3
{
char a[13];
char b;
};
cout<<sizeof(u)<<endl; // 8
cout<<sizeof(u2)<<endl; // 16
cout<<sizeof(u3)<<endl; // 13
都知道union的大小取决于它所有的成员中,占用空间最大的一个成员的大小。所以对于u来说,大小就是最大的double类型成员a了,所以sizeof(u)=sizeof(double)=8。但是对于u2和u3,最大的空间都是char[13]类型的数组,为什么u3的大小是13,而u2是16呢?关键在于u2中的成员int b。由于int类型成员的存在,使u2的对齐方式变成4,也就是说,u2的大小必须在4的对界上,所以占用的空间变成了16(最接近13的对界)。
在深入一点点:
union un
{
int a;
char b[5];
};
class CA
{
char a;
un b;
};
Sizeof(un) = 8;
所以 sizeof(CA) = 1+8 = 9 .因为9不是int的整数倍,需要填充3个。 所以最后是12.
再举一个例子:
union un
{
double a;
char b[9];
};
class CA
{
char a;
un b;
};
Sizeof(un) = 16;
所以 sizeof(CA) = 1 + 16 =17。 17不是double的整数倍,需要填充7个。所以最后是24.
在学习 #pragmapack(n)的问题。
这里的n必须是2的幂级,也就是 n必须是1,2,4,8,16,32……,如果n不是上面的值,会提示warning,并且当成默认处理。
#pragma pack(1) // 就是一字节对齐。这个是比较清楚的。 把所有成员的大小累积起来就没问题了。例子如下
#pragma pack(1)
class A {
int a;
bool b;
char c;
double d;
};
sizeof(A)=sizeof(int)+sizeof(bool)+sizeof(char)+sizeof(double;
sizeof(A) = 4+ 1+ 1 +8 = 14 . 呵呵,这是没问题的。
好了,今天就写到这里欢迎大家指正。谢谢。
Ps:需要着重理解的就是两条,再强调一遍。王雪刚看好了。
1. 每种类型的排列位置的偏移量必须是它的整数倍。
例如 class A{ char a, double b;}; 先对 char a排列,因为a的大小是1, 0是1的整数倍,所以没问题,第一个位置就是放着char a。(另外说一句0是任何数的整数倍,类当中的第一个成员都可以直接放置) 放完a之后,编译量变成了1,1不是8(double)的整数倍,所以需要填充7个,编译量成8的倍数之后,才可以放置double b;
加入 class B { double b, char a;}; 偏移量0是8的整数倍,所以直接放置double b没问题,然后编译量变成了8,8是size(char)的整数倍,所以直接放置char 啊;
2. 在前面的基础上放好之后,再判断总和是不是类中最大类型的整数倍。 sizeof(A) = 1 +7 + 8 = 16, 16是double的整数倍,所以最终结果就是16;
sizeof(B) = 8 +1 = 9; 9 不是 double的整数倍所以要填充 填充 到是double的整数倍。9+7= 16; 所以最终解决就是16的整数倍。
其实就这两条结论。再复杂的情况也遵守这两条。
还有枚举类型,枚举类型的大小就是4. 所以枚举比较简单,易操作。就不再对枚举再详细举例了。
再有就是在类中有Static类型的变量,这个就不属于我说范围之内了,这个的看C++基础了,了解Static类型的成员是由所以的对象共用一份就知道Static类型不包含在类中了。