深入理解sizeof+C语言数据类型+内存补齐

第一个例子:
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位置,因此是10+1
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


第二个例子:

数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如:
1.fun(char [8])
2.fun(char [])都等价于 fun(char *) 在C++里传递数组永远都是传递指向数组首元素的指针,

void printfsize(char p[100])
{
    std::cout<<"p[100] size"<<sizeof(p)<<" "<<std::endl;
}

输出结果为 4.

void test_size(char (&param)[10])

{

   int size_3 = sizeof(param);

   std::cout<<"size_3"<<size_3<<std::endl;

}

输出结果为 10.

int size_1 = sizeof(char&);    --->    1

int size_2 = sizeof(char[2]); --->    2


第三个例子:

union分到的内存等于它占内存最大的那个成员所需内存。

union fuck_union

{

    short a,b;

    unsigned c:2, d:1;

};

sizeof(fuck_union)  输出 4。

union fuck_union

{

    short a,b;

};

sizeof(fuck_union)  输出 2。


第四个例子:

sizeof还可以用函数做参数,比如:
1.short f();
2.printf("%d\n", sizeof(f()));

输出的结果是sizeof(short),即2。

int f()  输出结果为4。

class A

{

void FuckB(){};

};

printf("%d\n",  sizeof(&A::FuckB));

输出 4。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

字符对齐

计算结构变量的大小就必须讨论数据对齐问题。为了CPU存取的速度最快(这同CPU取数操作有关,详细的介绍可以参考一些计算机原理方面的书),C++在 处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。当然这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。 visual studio里的内存补齐是在项目属性-》C/C++-》代码生成-》结构成员对齐,一般是默认值,还可以设为1、2、4、8、16字节,分别表示为结构 体(struct、class,不包括union,union分到的内存等于它占内存最大的那个成员所需内存)内存分配时的最小单位为1、2、4、8、 16字节,但是如果设置的值比结构体中占内存最大的那个成员所需内存还大,则设置无效。默认值就是指以占内存最大的那个成员所需内存为最小单位。


class X

{
        char c;    //1byte
        int i;        //4byte
        short s;   //2byte

};

输出是 12


值得注意的是
class X

{
    char c;   //1byte
    short s;  //2byte
    int i;       //4byte

}

输出是 8


    class X{
        char c;//1byte

        short s;//2byte
        int i;//4byte

         };

 

设置的值             1         2        4         8        16 
    
默认值sizeof(X)    7        8         8        8         8 



















第二个例子:
01.class X
02.{
03.int i;
04.int j;
05.char k;
06.};
07.X x;
08.cout<<sizeof(X)<<endl; 结果 12 ===》内存补齐
09.cout<<sizeof(x)<<endl; 结果 12 同上

第三个例子:
1.char szPath[MAX_PATH]

如果在函数内这样定义,那么sizeof(szPath)将会是MAX_PATH,但是将szPath作为虚参声明时(void fun(char szPath[MAX_PATH])),sizeof(szPath)却会是4(指针大小)

三、sizeof深入理解。

1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。

2.sizeof是算符,strlen是函数。

3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。sizeof还可以用函数做参数,比如:
1.short f();
2.printf("%d\n", sizeof(f()));

输出的结果是sizeof(short),即2。

4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。

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后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。

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++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(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)都不是正确形式

四、结束语

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给出其指针的大小。 

    计算结构变量的大小就必须讨论数据对齐问题。为了CPU存取的速度最快(这同CPU取数操作有关,详细的介绍可以参考一些计算机原理方面的书),C++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。当然这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。visual studio里的内存补齐是在项目属性-》C/C++-》代码生成-》结构成员对齐,一般是默认值,还可以设为1、2、4、8、16字节,分别表示为结构体(struct、class,不包括union,union分到的内存等于它占内存最大的那个成员所需内存)内存分配时的最小单位为1、2、4、8、16字节,但是如果设置的值比结构体中占内存最大的那个成员所需内存还大,则设置无效。默认值就是指以占内存最大的那个成员所需内存为最小单位

      代码里加#pragma pack (n) //n:1 2 4 8 16也是一样的效果

     class X{
        char c;//1byte
        int i;//4byte

        short s;//2byte

         };

设置的值    1          2        4    8  16 
    
默认值  sizeof(X)
    

7    8    12   12  12  12
    
值得注意的是

      class X{
        char c;//1byte

        short s;//2byte
        int i;//4byte

         };

 

设置的值    1          2        4    8  16 
    
默认值  sizeof(X)  7  8  8  8  8  8  8

设置为1、2的时候都好理解,设置为4的时候为什么不是12呢?因为编译器按顺序为成员变量分配内存,char+short总共3byte,还不到4byte,补齐为4byte即可,再加4byteint,总共8byte
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章