sizeof用法总结:
例子1:
<span style="font-size:18px;">int main(int argc, char *argv[])
{
char *ss = "0123456789";
cout<<sizeof(ss)<<endl; //结果为4,ss是指向字符串常量的字符指针,类型为指针。
cout<<sizeof(*ss)<<endl; //结果为1,*ss是字符串的第一个字符,类型为char。
return 0;
}</span>
例子2:
<span style="font-size:18px;">int main(int argc, char *argv[])
{
char ss[] = "0123456789";
cout<<sizeof(ss)<<endl; //结果为11,ss为数组,计算到数组末尾的"\0",共11个字符。
cout<<sizeof(*ss)<<endl; //结果为1,*ss同样是字符串的第一个字符。
return 0;
}</span>
<span style="font-size:18px;">int main(int argc, char *argv[])
{
char ss[100] = "0123456789";
cout<<sizeof(ss)<<endl; //结果为100,ss数组在内存中分配了100个char类型的空间
cout<<strlen(ss)<<endl; //结果为10,计算字符串的长度,知道"\0"为止,这里字符数组类型转换为char*
return 0;
}</span>
<span style="font-size:18px;">int main(int argc, char *argv[])
{
int ss[100] = {0,1,2,3,4,5,6,7,8,9};
cout<<sizeof(ss)<<endl; //结果为400,ss数组在内存中分配了100个int类型的空间
cout<<strlen(ss)<<endl; //错误,strlen参数只能是char*,而且是以"\0"结尾的
return 0;
}</span>
<span style="font-size:18px;">class X
{
int i;
int j;
char k;
};
int main(int argc, char *argv[])
{
X x;
cout<<sizeof(x)<<endl; //结果为12,x的类型为X
cout<<sizeof(X)<<endl; //结果为12,4+4+1补3,内存补齐,具体详情参考上一篇博文
return 0;
}</span>
sizeof 与strlen 比较总结:
1. sizeof是运算符,strlen是函数
2. sizeof运算符的操作结果是size_t,它在头文件中的typedef为 unsigened int 类型,
3. sizeof可以用类型做参数,strlen只能用char *做参数,且字符串末尾必须以“\0”结尾。sizeof还可以以函数作参数,比如:
<span style="font-size:18px;">short f()
printf("%d\n",sizeof(f())); //实际为sizeof(short),结果为2</span>
4.数组做sizeof的参数不退化,传递给strlen就退化成char*指针,数组作为参数传给函数时传的是指针而不是数组,该指针指向数组的首地址,如fun(char[8]),func(char[])都等价于fun(char*)。编译器不知道数组的大小,如果函数想要知道数组的大小,需要这样做:
<span style="font-size:18px;">func(unsigned char *p1,int len)
{
unsigned char *buff = new unsigned char[len+1];
memcpy(buf,p1,len);
<span style="font-family: Arial, Helvetica, sans-serif;">}</span></span>
<span style="font-size:18px;">//例题:
char var[10];
int test(char var[])
{
return sizeof(var); var[]等价于var*,已经退化成为指针了,指针的大小输出为4.
}</span>
5. 大部分编译器在编译的时候就把sizeof计算出来了,所以sizeof(x)可以直接用来定义数组的维数。而strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度,而不是计算类型或变量占内存的大小。
<span style="font-size: 18px;">char str[20] = "0123456789";
int a = strlen(str); //a=10
int b[sizeof(str)] ; //b是维度为20的int型数组</span>
6
.sizeof后如果是类型必须加括号,如果是变量可不用加括号,这是因为sizeof是操作符,而不是函数。
7.sizeof()不是括号里的内容是不被编译的,而是被类型替代,如int a = 8;sizeof(a)在编译过程中,只是被替换成sizeof(int),结果为4,同样,sizeof(a=6)执行后,a的值还是为8不变。
8.unisgned 影响的只是最高位bit的意义,数据长度是不会改变的,所以sizeof(unsigned int) = sizeof(int).
9.自定义的类型sizeof取值等于它的类型原形:typedef short WORD,sizeof(WORD)== sizeof(short)
10.对函数使用sizeof,在编译期间会被函数的返回值类型替代。
11.只要是指针,sizeof计算的大小就是4。
12.数组的大小是各维数的乘积*数组元素的大小。
sizeof计算类的大小:
类的sizeof大小一般是类中的所有成员的sizeof大小之和,这个就不用多说。不过有几点需要注意:
1)当类中含有虚成员函数的时候,例如:
<span style="font-size:18px;">class B
{
float a;
public:
virtual void fun(void);
}</span>
此时sizeof(B)的大小为8,而不是4。因为在类中隐藏了一个指针,该指针指向虚函数表,正因为如此,使得C++能够支持多态,即在运行时绑定函数的地址。
2)另一个要注意的是,当类中没有任何成员变量,也没有虚函数的时候,该类的大小是多少呢?例如:
<span style="font-size:18px;">class B2
{
void fun(void);
}</span>
此时sizeof(B2)的值是多少呢?在C++早期的编译器中,这个值为0;然而当创建这样的对象时,它们与紧接着它们后面的对象有相同的地址。比如:B2 b2;
int a;
那么对象b2与变量a有相同的地址,这样的话对对象b2地址的操作就会影响变量a。所以在现在大多数编译器中,该值的大小为1。
3)类中的静态成员、及普通成员函数是不算入类的内存大小的
<span style="font-size:18px;">class A
{
int print();
int b;
const int c;
static int d;
};</span>
此时sizeof(A)的大小为8,分别为b和c的变量之和
4)在类的继承中,如果是普通继承,子类的大小是子类的大小加上其所父类的大小之和,如果是虚继承,除了加上父类的大小,还需要计算指向父类的虚指针大小。
实例如下:
<span style="font-size:18px;">class A
{
int virtual aa(){};
char a;
const int c;
static int d;
};
class B : public A
{
char j[3];
public:
int virtual bb(){};
};
class C : public virtual B
{
char i[3];
public:
int virtual cc(){};
};
int main()
{
cout<<sizeof(A)<<endl; //结果为12
cout<<sizeof(B)<<endl; //结果为16
cout<<sizeof(C)<<endl; //结果为28
return 0;
} </span>
sizeof(A):虚函数指针(4)+ char型成员(原为1,位数补齐为4) + const int 型成员(4) 合计12
sizeof(B):char型数组(原为3,位数补齐为4) + 父类A的大小 (12) 合计16,需要注意的是,这里面B类中的虚函数和其父类的虚函数共用一个虚表,因此只用计算父类指向虚函数的指针,子类中忽略这一项。
sizeof(C):这里是虚拟继承,子类不与父类公用虚函数表,因此子类的指针需要单独计算,char型数组(4)+ 虚函数指针(4)+ 虚基类偏移量表指针(4)+ 父类的大小(16) 合计28
以下部分引用自:http://blog.csdn.net/jhj735412/article/details/7580498
类中各种情况下内存大小计算总结:
1.普通单继承,只需将自身成员变量的大小加上父类大小(父类中 有虚函数,子类中不管有没有)若父类没有虚函数,则子类大小需要加上指向虚表的指针大小。
2.普通多继承,若几个父类都有虚表,则子类与第一个父类公用一个虚表指针,其他有几个有虚函数的父类则就有几个虚表指针。
3.虚拟单继承,此时若子类有虚函数则加上一个自身的虚表指针的大小,(若没有则不加)再加上自身的成员变量大小,还要加上一个虚类指针ptr_sonclass_fatherclass,最后加上父类的大小。
4.多重虚拟继承,此时若子类有虚函数则加上一个自身的虚表指针的大小,(若没有则不叫)再加上自身的成员变量大小,还要加上 一个公用的虚类指针(不管有几个虚拟父类,只加一个),在加上所有父类的大小。
5.普通、虚拟混合多继承,此时子类的大小为自身大小(若子类或普通父类有虚函数,则为成员变量+虚表指针大小;若都没虚函数,则就为成员变量大小),加上一个虚类指针大小,在加上虚拟父类的大小,在加上普通父类的大小(除虚表指针,因为它和子类公用一个虚表指针)。