sizeof(类)

基本概念


1.类的大小为类的非静态成员数据的类型大小之和,也就是说静态成员数据不作考虑。

2.普通成员函数与sizeof无关。

3.虚函数由于要维护在虚函数表,所以要占据一个指针大小,也就是4字节。

4.类的总大小也遵守类似class字节对齐的,调整规则。

一个类的实例化对象所占空间的大小? 注意不要说类的大小,是类的对象的大小.

首先,类的大小是什么?确切的说,类只是一个类型定义,它是没有大小可言的。 用sizeof运算符对一个类型名操作,得到的是具有该类型实体的大小。

如果 Class A; A obj; 那么sizeof(A)==sizeof(obj) 那么sizeof(A)的大小和成员的大小总和是什么关系呢,很简单,一个对象的大小大于等于所有非静态成员大小的总和。 
参照:http://www.myexception.cn/program/1666528.html

sizeof一个空类,带有构造函数的,以及虚函数的

#include<iostream>
using namespace std;
class A
{
};
class B
{
public:
    B() {}
    ~B() {}
};
class C
{
public:
    C() {}
    virtual ~C() {}
};
int main()
{
    cout <<"sizeof一个空类的大小为  "<< sizeof(A) << endl;//1
    cout << "sizeof一个带有构造函数和析构函数的类的大小为  " << sizeof(B) << endl;//1
    cout << "sizeof一个带有虚函数的类的大小为  " << sizeof(C) << endl;//4
    return 0;

}

上述结果分别是:1,1,4

class A是一个空类型,它的实例不包含任何信息,本来求sizeof应该是0。但当我们声明该类型的实例的时候,它必须在内存中占有一定的空间,否则无法使用这些实例。至于占用多少内存,由编译器决定。Visual Studio 2008中每个空类型的实例占用一个byte的空间。

class Bclass A的基础上添加了构造函数和析构函数。由于构造函数和析构函数的调用与类型的实例无关(调用它们只需要知道函数地址即可),在它的实例中不需要增加任何信息。所以sizeof(B)和sizeof(A)一样,在Visual Studio 2008中都是1。

class Cclass B的基础上把析构函数标注为虚拟函数。C++的编译器一旦发现一个类型中有虚拟函数,就会为该类型生成虚函数表,并在该类型的每一个实例中添加一个指向虚函数表的指针。在32位的机器上,一个指针占4个字节的空间,因此sizeof(C)是4。

C++标准规定类的大小不为0,空类的大小为1,当类不包含虚函数和非静态数据成员时,其对象大小也为1。 如果在类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针指向虚函数表VTable,在32位机器上,一个对象会增加4个字节来存储此指针,它是实现面向对象中多态的关键。而虚函数本身和其他成员函数一样,是不占用对象的空间的。

sizeof类中带有成员变量的

class D {

    char ch;

    void func() { }

};

class E {

    char ch1; //占用1字节

    char ch2; //占用1字节

    virtual void func() { }

};
class F {

    int in;

    virtual void func() { }

};
    cout << "D的大小"<< sizeof(D) << endl;//1
    cout << "E的大小" << sizeof(E) << endl;//8
    cout << "F的大小" << sizeof(E) << endl;//8

注意要对齐!

sizeof求继承类的大小

class G :public A, public C {};
class H :public A, public B, public C {};
class I :public A, public C, public B {};
   cout << "G的大小" << sizeof(G) << endl;//4
    cout << "H的大小" << sizeof(H) << endl;//8
    cout << "I的大小" << sizeof(I) << endl;//8

等于基类的和,但是要注意字节对齐。不过这个和一般的字节对齐还不一样,比如I,按理说应该是4(1)+4+4(1),但是实际应该是4(1+1)+4。

一个很奇怪的地方就是:

class A
{
};
class A1
{
};
class A2
{
};
class A3
{
};
class A4
{
};
class G :public A{}//sizeof(G)=1
class G :public A, public B{}//sizeof(G)=1
class G :public A, public B{} ,public A1{}//sizeof(G)=1
class G :public A, public B ,public A1, public A2{}//sizeof(G)=3

这个结果不明白! 
????

class H :public A, public C, public A1, public A2, public A3, public A4, public B {};//sizeof(H)=12
class H :public A, public C, public A1, public A2, public A3,  public B {};//sizeof(H)=8

大致规律就是继承2个空类时,占1,每多加1个会多1。

class J {
private:
    char a1;
    int data;
    char a2;
};
cout << "J的大小" << sizeof(J) << endl;//12 这个有字节对齐的。
摘自:http://www.myexception.cn/program/1666528.html

//编译器为每个有虚函数的类都建立一个虚函数表(其大小不计算在类中),并为这个类安插一个指向虚函数表的指针,即每个有虚函数的类其大小至少为一个指针的大小4   
class A
{   
public:   
    int a;   
    void Function();   
};   
class B
{   
public:   
    int a;   
    virtual void Function();   
};   
class C : public B
{   
public:   
    char b;   
};   
class D : public B
{   
public:   
    virtual void Function2();   
};   
class E
{   
public:   
    static void Function();   
};   
class staticE   
{   
    static int intVar;   
    static void fun(){} 
};  
void test1()
{
    cout<<"sizeof(A)="<<sizeof(A)<<endl;//4   (内含一个int,普通函数不占大小)   
    cout<<"sizeof(B)="<<sizeof(B)<<endl;//8   (一个int ,一个虚函数表指针)   
    cout<<"sizeof(C)="<<sizeof(C)<<endl;//12   (一个int ,一个虚函数表指针,一个char ,再加上数据对齐)  
    cout<<"sizeof(D)="<<sizeof(D)<<endl;//8 (一个int ,一个虚函数表指针,多个虚函数是放在一个表里的,所以虚函数表指针只要一个就行了)   
    cout<<"sizeof(E)="<<sizeof(E)<<endl;//1   (static 函数不占大小,空类大小为1)   
    cout<<"sizeof(staticE)="<<sizeof(staticE)<<endl;//1   静态数据成员不计入类内   
}
class cA   
{   
public:   
    virtual void PrintA1(void){}    
    virtual void PrintA2(void){}   
};   
class cB   
{   
public:   
    virtual void PrintB(void){}    
};   
class cC   
{   
public:   
    virtual void PrintC(void){}    
};   
class cD : public cA, public cB, public cC 
{   
};   
class cE : public cA, public cB, public cC   
{   
public:   
    virtual void PrintE(void){}    
};   
void test2()
{
    cout<<"sizeof(cD)="<<sizeof(cD)<<endl;//12 如果一个类里面什么也不实现,只实现一个或多个虚函数的话,测它的sizeof会得到4,但如果一个类从多个类继承,并且它的多个基类有虚函数的话,它就会有多个虚函数表了,这个在COM也有体现.
    cout<<"sizeof(cE)="<<sizeof(cE)<<endl;//12    
}
class dA 
{
    int a;
    virtual ~dA(){}
};
class dB:virtual public dA
{
    virtual void myfunB(){}
};
class dC:virtual public dA
{
    virtual void myfunC(){}
};
class dD:public dB,public dC
{
    virtual void myfunD(){}
};
void test3()
{ 
    cout<<"sizeof(dA)="<<sizeof(dA)<<endl;//8  
    cout<<"sizeof(dB)="<<sizeof(dB)<<endl;//12 
    cout<<"sizeof(dC)="<<sizeof(dC)<<endl;//12   
    cout<<"sizeof(dD)="<<sizeof(dD)<<endl;//16  
    //解释:A中int+虚表指针。B,C中由于是虚继承因此大小为A+指向虚基类的指针,B,C虽然加入了自己的虚函数,但是虚表指针是和基类共享的,因此不会有自己的虚表指针。D由于B,C都是虚继承,因此D只包含一个A的副本,于是D大小就等于A+B中的指向虚基类的指针+C中的指向虚基类的指针。
    //如果B,C不是虚继承,而是普通继承的话,那么A,B,C的大小都是8(没有指向虚基类的指针了),而D由于不是虚继承,因此包含两个A副本,大小为16. 注意此时虽然D的大小和虚继承一样,但是内存布局却不同。
}
class T1   
{    
};   
class T2 : public T1   
{    
};   
class T3 : public T1   
{    
    int a;
};   

class M1   
{     
    virtual void GetM()=0;
};   
class M2 
{    
    virtual void GetM2()=0;
    virtual void Get();
};   
class M3 : public M1, public M2 
{    
    int a;
};   
void test4()
{
    cout<<"sizeof(T2)="<<sizeof(T2)<<endl;//1   继承一个空父类,这时sizeof(父类)=0
    cout<<"sizeof(T3)="<<sizeof(T3)<<endl;//4   同上
    cout<<"sizeof(M1)="<<sizeof(M1)<<endl;// 4
    cout<<"sizeof(M2)="<<sizeof(M2)<<endl;// 4
    cout<<"sizeof(M3)="<<sizeof(M3)<<endl;// 12  抽象函数与虚函数一样
}

void main()
{    
    test1();
    test2();
    test3();
    test4();
} 
/*虚函数表(http://www.uml.org.cn/c%2B%2B/200811143.asp) 
C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。
对C++了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。 在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了 这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。
这里我们着重看一下这张虚函数表。C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
debug时,在局部变量窗口中可以看到,虚函数表
*/

sizeof 求含有静态数据成员的类的大小

class K {
private:
    int data;
    static int data1;
};
int K::data1 = 0;

cout << “K的大小” << sizeof(K) << endl;//4

K的静态数据成员被编译器放在程序的一个global  data members中,它是类的一个数据成员.但是它不影响类的大小,不管这个类实际产生 了多少实例,还是派生了多少新的类,静态成员数据在类中永远只有一个实体存在,而类的非静态数据成员只有被实例化的时候,他们才存在.但是类的静态数据成员一旦被声明,无论类是否被实例化,它都已存在.可以这么说,类的静态数据成员是一种特殊的全局变量.

小总结:

从以上的几个例子不难发现类的大小:

1.为类的非静态成员数据的类型大小之和.

2.由编译器额外加入的成员变量的大小,用来支持语言的某些特性(如:指向虚函数的指针).

3.为了优化存取效率,进行的边缘调整(对齐).

4 与类中的构造函数,析构函数以及其他的成员函数无关.

sizeof求各个类型的大小

第一个例子: 基本数据类型的sizeof
这里的基本数据类型指shortintlongfloatdouble这样的简单内置数据类型,由于它们都是和系统相关的,所以在不同的系统下取值可能不同,这务必引起我们的注意,尽量不要在这方面给自己程序的移植造成麻烦。
一般的,在32位编译环境中,
sizeof int; //4byte
sizeof short; //2
sizeof long; //4
sizeof float; //4
sizeof double; //8
sizeof char; //1
sizeof p; //4
sizeof WORD; //2
sizeof DWORD; //4
view source print?
一般的,在64位编译环境中,int8byte ,指针为8byte 。

第二个例子: 指针变量的sizeof
学过数据结构的你应该知道指针是一个很重要的概念,它记录了另一个对象的地址。既然是来存放地址的,那么它当然等于计算机内部地址总线的宽度。所以在32位计算机中,一个指针变量的返回值必定是4(注意结果是以字节为单位),可以预计,在将来的64位系统中指针变量的sizeof结果为8char* pc = "abc";
int* pi;
string* ps;
char** ppc = &pc;<pre name="code" class="java">char* pc = "abc";
int* pi;
string* ps;
char** ppc = &pc;
void (*pf)(); // 函数指针
sizeof( pc ); // 结果为4
sizeof( pi ); // 结果为4
sizeof( ps ); // 结果为4
sizeof( ppc ); // 结果为4
sizeof( pf ); // 结果为4

指针变量的sizeof值与指针所指的对象没有任何关系,正是由于所有的指针变量所占内存大小相等,所以MFC消息处理函数使用两个参数WPARAM、LPARAM就能传递各种复杂的消息结构(使用指向结构体的指针)。
第三个例子: 数组的sizeof
数组的sizeof值等于数组所占用的内存字节数,c风格字符串末尾还存在一个NULL(\0)终止符
01.
char* ss = "0123456789";
02.
sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针
03.
sizeof(*ss) 结果 1 ===》*ss是第一个字符
04.

05.
char ss[] = "0123456789";
06.
sizeof(ss) 结果 11 ===》ss是数组,计算到\0位置,因此是101
07.
sizeof(*ss) 结果 1 ===》*ss是第一个字符
08.

09.
char ss[100] = "0123456789";
10.
sizeof(ss) 结果是100 ===》ss表示在内存中的大小 100×1
11.
strlen(ss) 结果是10 ===》strlen是个函数内部实现是用一个循环计算到\0为止之前
12.

13.
int ss[100] = "0123456789";
14.
sizeof(ss) 结果 400 ===》ss表示再内存中的大小 100×4
15.
strlen(ss) 错误 ===》strlen的参数只能是char* 且必须是以''\0''结尾的
16.

17.
char q[]="abc";
18.
char p[]="a\n";
19.
sizeof(q),sizeof(p),strlen(q),strlen(p);
20.
结果是 4 3 3 2

自己写的一个例子:

char pp1[] = "a\\\n";
    cout << sizeof(pp1) << " " << strlen(pp1) << endl;//4 3(注意\\和\n分别代表\和换行,其实分别表示一个
    return 0;

一些朋友刚开始时把sizeof当作了求数组元素的个数,现在,你应该知道这是不对的,那么应该怎么求数组元素的个数呢?Easy,通常有下面两种写法: 
char a1[] = “abc”; 
int c1 = sizeof( a1 ) / sizeof( char ); // 总长度/单个元素的长度 
int c2 = sizeof( a1 ) / sizeof( a1[0] ); // 总长度/第一个元素的长度 
void foo3(char a3[3]) 
{ 
int c3 = sizeof( a3 ); // c3 == 4 

void foo4(char a4[]) 
{ 
int c4 = sizeof( a4 ); // c4 == 4 

这里函数参数a3已不再是数组类型,而是蜕变成指针,相当于char* a3,为什么?仔细想想就不难明白,我们调用函数foo1时,程序会在栈上分配一个大小为3的数组吗?不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以a3自然为指针类型(char*),c3的值也就为4。

第四个例子:结构体的sizeof
1为什么需要字节对齐?
计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。

2字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
struct s1
{
char a;
double b;
int c;
char d; 
};

struct s2
{
char a;
char b;
int c;
double d;
};
cout<<sizeof(s1)<<endl; // 24
cout<<sizeof(s2)<<endl; // 16

    //同样是两个char类型,一个int类型,一个double类型,但是因为对齐问题,导致他们的大小不同。计算结构体大小可以采用元素摆放法,我举例子说明一下:首先,CPU判断结构体的对界,根据上面的结论,s1和s2的对界都取最大的元素类型,也就是double类型的对界8。然后开始摆放每个元素(满足准则1)。
  //对于s1,首先把a放到8的对界,假定是0,此时下一个空闲的地址是1,但是下一个元素d是double类型,要放到8的对界上,离1最接近的地址是8了,所以d被放在了8(满足准则2),此时下一个空闲地址变成了16,下一个元素c的对界是4,16可以满足,所以c放在了16,此时下一个空闲地址变成了20,下一个元素d需要对界1,也正好落在对界上,所以d放在了20,结构体在地址21处结束。由于s1的大小需要是8的倍数,所以21-23的空间被保留,s1的大小变成了24(满足准则3)。
  //对于s2,首先把a放到8的对界,假定是0,此时下一个空闲地址是1,下一个元素的对界也是1,所以b摆放在1,下一个空闲地址变成了2;下一个元素c的对界是4,所以取离2最近的地址4摆放c,下一个空闲地址变成了8,下一个元素d的对界是8,所以d摆放在8,所有元素摆放完毕,结构体在15处结束,占用总空间为16,正好是8的倍数。
通过上面的叙述,我们可以得到一个公式:
结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:
sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof( trailing padding )
2) 基本类型是指前面提到的像charshortintfloatdouble这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。
看下面的例子:
struct s1
{
char a[8];
};

struct s2
{
double d;
};

struct s3
{
s1 s;
char a;
};

struct s4
{
s2 s;
char a; 
};
cout<<sizeof(s1)<<endl; // 8
cout<<sizeof(s2)<<endl; // 8
cout<<sizeof(s3)<<endl; // 9
cout<<sizeof(s4)<<endl; // 16;


  s1和s2大小虽然都是8,但是s1的对齐方式是1,s2是8double),所以在s3和s4中才有这样的差异。
  所以,在自己定义结构体的时候,如果空间紧张的话,最好考虑对齐因素来排列结构体里的元

4)“空结构体”(不含数据成员)的大小不为0,而是1。试想一个“不占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢?于是,“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占位了。如下: 
struct S5 { }; 
sizeof( S5 ); // 结果为1

第五个例子:含位域结构体的sizeof
位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构体的sizeof,只是考虑到其特殊性而将其专门列了出来。
C99规定intunsigned intbool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。
使用位域的主要目的是压缩存储,其大致规则为:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。
示例1struct BF1
{
    char f1 : 3;
    char f2 : 4;
    char f3 : 5;
};
其内存布局为:
| f1  |  f2   | |  f3     |     |
---------------------------------
|  | | |  | | |  | | | | | |    | | | |
---------------------------------
0     3     7 8         13    16 (byte)
位域类型为char,第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中,而f3只能从下一个字节开始。因此sizeof(BF1)的结果为2。
示例2struct BF2
{
    char f1 : 3;
    short f2 : 4;
    char f3 : 5;
};
| f1  |  f2   | |  f3     |     |
---------------------------------
|  | | |  | | |  | | | | | |    | | | |
---------------------------------
0     3     7 8         13    16 (byte) 压缩
f1                                  f2             
不压缩时,首先把f1放到1的对界,假定是0,此时下一个空闲的地址是1,但是下一个元素f2是short类型,要放到2的对界上,离1最接近的地址是2了,所以f2被放在了2(满足准则2),此时下一个空闲地址变成了4,下一个元素 f3的对界是14可以满足,所以 f3放在了4,此时下一个空闲地址变成了5,结构体在地址5处结束。由于BF2的大小需要是2的倍数,所以5的空间被保留,BF2的大小变成了6(满足准则3)。
由于相邻位域类型不同,在VC6中其sizeof6,在Dev-C++中为2。
示例3struct BF3
{
    char f1 : 3;
    char f2;
    char f3 : 5;
};

非位域字段穿插在其中,不会产生压缩,在VC6和Dev-C++中得到的大小均为3。

补充:不要让double干扰你的位域 
  在结构体和类中,可以使用位域来规定某个成员所能占用的空间,所以使用位域能在一定程度上节省结构体占用的空间。不过考虑下面的代码: 
struct s1 
{ 
 int i: 8; 
 int j: 4; 
 double b; 
 int a:3; 
}; 

struct s2 
{ 
 int i; 
 int j; 
 double b; 
 int a; 
}; 

struct s3 
{ 
 int i; 
 int j; 
 int a; 
 double b; 
}; 

struct s4 
{ 
 int i: 8; 
 int j: 4; 
 int a:3; 
 double b; 
}; 

cout<<sizeof(s1)<<endl; // 24 
cout<<sizeof(s2)<<endl; // 24 
cout<<sizeof(s3)<<endl; // 24 
cout<<sizeof(s4)<<endl; // 16 


  可以看到,有double存在会干涉到位域(sizeof的算法参考上一节),所以使用位域的的时候,最好把float类型和double类型放在程序的开始或者最后。

第七个例子:联合体的sizeof 
结构体在内存组织上是顺序式的,联合体则是重叠式,各成员共享一段内存,所以整个联合体的sizeof也就是每个成员sizeof的最大值。结构体的成员也可以是复合类型,这里,复合类型成员是被作为整体考虑的。 
所以,下面例子中,U的sizeof值等于sizeof(s)。 
union U 
{ 
int i; 
char c; 
S1 s; 
};

深入理解

三、sizeof深入理解。
1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
2.sizeof也可以对一个函数调用求值,其结果是函数返回类型的大小,函数并不会被调用,我们来看一个完整的例子:
char foo()
{   printf("foo() has been called./n");
    return 'a';
}
int main()
{
   size_t sz = sizeof( foo() ); // foo() 的返回值类型为char,所以sz = sizeof( char ),foo()并不会被调用
    printf("sizeof( foo() ) = %d/n", sz); 
}

sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。sizeof还可以用函数做参数,比如:
1.
short f();
2.
printf("%d\n", sizeof(f()));
输出的结果是sizeof(short),即23. sizeof的常量性
sizeof的计算发生在编译时刻,所以它可以被当作常量表达式使用,如:
char ary[ sizeof( int ) * 10 ]; // ok

最新的C99标准规定sizeof也可以在运行时刻进行计算,如下面的程序在Dev-C++中可以正确执行:
int n;
n = 10; // n动态赋值
char ary[n]; // C99也支持数组的动态定义
printf("%d/n", sizeof(ary)); // ok. 输出10

但在没有完全实现C99标准的编译器中就行不通了,上面的代码在VC6中就通不过编译。所以我们最好还是认为sizeof是在编译期执行的,这样不会带来错误,让程序的可移植性强些。
4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
char ss[100] = "0123456789";
10.
sizeof(ss) 结果是100 ===》ss表示在内存中的大小 100×1
11.
strlen(ss) 结果是10 ===》strlen是个函数内部实现是用一个循环计算到\0为止之前
5.大部分编译程序 在编译的时候就把sizeof计算过了 是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因
1.
char str[20]="0123456789";
2.
int a=strlen(str); //a=10;
3.
int b=sizeof(str); //而b=20;
6.strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。
7.sizeof是算符,strlen是函数。sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
sizeof有三种语法形式,如下:
1) sizeof( object ); // sizeof( 对象 );
2) sizeof( type_name ); // sizeof( 类型 );
3) sizeof object; // sizeof 对象;
所以,
int i;
sizeof( i ); // ok
sizeof i; // ok
sizeof( int ); // ok
sizeof int; // error

既然写法3可以用写法1代替,为求形式统一以及减少我们大脑的负担,第3种写法,忘掉它吧!
实际上,sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的不同对象其sizeof值都是一致的。这里,对象可以进一步延伸至表达式,即sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式进行计算。如:
sizeof( 2 ); // 2的类型为int,所以等价于 sizeof( int );
sizeof( 2 + 3.14 ); // 3.14的类型为double,2也会被提升成double类型,所以等价于 sizeof( double );

8.当适用了于一个结构类型时或变量, sizeof 返回实际的大小; 当适用一静态地空间数组, sizeof 归还全部数组的尺 寸。 sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
9.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如:
1.
fun(char [8])
2.
fun(char [])
都等价于 fun(char *) 在C++里传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小如果想在函数内知道数组的大小, 需要这样做:进入函数后用memcpy拷贝出来,长度由另一个形参传进去
1.
fun(unsiged char *p1, int len)
2.
{
3.
unsigned char* buf = new unsigned char[len+1]
4.
memcpy(buf, p1, len);
5.
}
有关内容见: C++ PRIMER?
10.计算结构变量的大小就必须讨论数据对齐问题。为了CPU存取的速度最快(这同CPU取数操作有关,详细的介绍可以参考一些计算机原理方面的书),C++在处理数据时经常把结构变量中的成员的大小按照48的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。当然这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。MS VC++中的对齐设定,有时候sizeof得到的与实际不等。一般在VC++中加上#pragma pack(n)的设定即可.或者如果要按字节存储,而不进行数据对齐,可以在Options对话框中修改Advanced compiler页中的Data alignment为按字节对齐。
11.sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式
C99标准规定,函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算sizeof值,即下面这些写法都是错误的:
sizeof( foo ); // error

void foo2() { }
sizeof( foo2() ); // error

struct S
{
    unsigned int f1 : 1;
    unsigned int f2 : 5;
    unsigned int f3 : 12;
};
sizeof( S.f1 ); // error



四、结束语
sizeof使用场合。
1.sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如: 
1.
void *malloc(size_t size), 
2.
size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。
2.用它可以看看一类型的对象在内存中所占的单元字节。
1.
void * memset(void * s,int c,sizeof(s))
3.在动态分配一对象时,可以让系统知道要分配多少内存。
4.便于一些类型的扩充,在windows中就有很多结构内型就有一个专用的字段是用来放该类型的字节大小。
5.由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof来代替常量计算。
6.如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值