现在的位置: 首页 > 综合 > 正文

vc 浅谈sizeof

2014年02月08日 ⁄ 综合 ⁄ 共 2760字 ⁄ 字号 评论关闭

此为“小紫”对sizeof的一些见解,所以发出来给大家分享下,发现网上对内存对齐的说法不统一,

所以才实验了一下,得出来了一个“标准”。(我知道网上有很多比我这篇文章更具体,更详细,但我会

努力把这篇文章写得通俗易懂,让大家更容易理解。另外,第五部分是我写这篇文章的原因)
    如果您有转载的欲望,请您能够保留这版权信息。这是读者们唯一可以信任的东西。(本篇文章在

WIN32平台下写,所以字节大小也以WIN32为标准)

本文首发至本人博客中.

   一、为什么要读这篇文章?
       这篇文章面对初学者设计,通过这篇文章来理解内存中类型或变量所占字节的“艺术”,如果觉

得本文太简单,我可以推荐一篇文章:《详细解析C语言中的sizeof》,本文有很多细节也是参考的那里

。如果前几个部分太简单,可以从第五部分看起。

   二、什么是sizeof?
        sizeof其实是一个操作符,而并非是一个函数,写成“括号形式”(我把加“()”的任何语句

形式都叫“括号形式”)只是它的一种普遍写法。sizeof可以得到操作符所占用内存字节数的大小。

sizeof操作符可以为变量、基本类型(int,float等都是基本类型)、结构体。

   三、sizeof的格式
       (1)对于变量有两种格式:
           ①sizeof(变量);
           ②sizeof 变量;这种格式是允许的。但是不普遍。
       (2)对于结构体和基本类型只有一种写法:
          sizeof(结构名字、基本类型名);

   四、注意!
       不确定所占内存大小的类型(包括不确定大小的共用结构(联合结构)等),void类型和函数等不可

以作为sizeof的操作符。sizeof的返回值为size_t(也就是unsigned int)。指针的大小根据编译器决定。

   五、sizeof的结果
       在开始正文之前,请大家看一个程序
段:
       long double p[2]={0.0};
       int abc(long double a[])
       {
         unsigned int fR=sizeof(a);
         return fR;
       }
       那么现在该告诉我,函数的返回值是多少?

        嗯,也许你会回答(只是也许,我知道,这个世界上不乏有高手的存在),返回值是12(一个

long double所占内存的字节为12),但是函数却返回了4。其实,这是编译器的一次“小恶作剧”,我们

都知道,编译器有两大任务:1.编译成可执行文件。2.优化代码。但是编译器为了简化编译,让数组在传

入函数的时候产生了意外,被当作了指针处理,以此来简化编译。所以结果返回的是sizeof(long

double*).嗯~~如果你不相信的话,我可以给你一个完整的程序
段去实验一下:
           #include <stdio.h>

           int abc(long double a[])
           {
              unsigned int fR=sizeof(a);
              return fR;
           }

           int main(void)
           {
             long double p[2]={0.0};
             printf("%d",abc(p));
             return 0;
           }

       各位也许认为上面那道题目太简单了。那么我们这次就可以来一个…………………………………

…更简单的了。
       struct M
       {
         char a;
         int b;
         long c;
       }
       如果我们现在来sizeof(M)那么得到的结果是什么呢?也许你这次会说是9,或15。(只是也许。

我知道,高手有很多。)但是正确的答案是16。下面我将为读者来解释下这个答案的名字:这是C99的一

个标准,它的名字叫内存对齐。CPU在访问内存对齐的变量的时候,速度会加快。可以说,这是标准跟我

们开的一个玩笑。
       当然,为了以后我们能够准确计算出结构体所占的空间,我将为电脑
前的您来讲解如何计算这种

“特殊的结果”。
       您有两种方法来理解“内存对齐”,但在文章的最后,我将会讲解这两种方法之间的微妙关系。
        1.在大多数编译器中,默认的内存对齐大小为8。当数据的大小大于8时,也会被当做8处理。当

然,你也可以更改。我们来依次理解:
         //我们先要知道,我们可以以8个字节为一个大单位,当然,这个8是可以更改的。
         char a; //那么char的字节为1,先进入到了这个“大单位”中
         int b;//int为4字节,大单位中还余下了7个小单位,也可以挤进去。
         long c;//long也为4字节,可是此时大单位中还只剩下了3个单位,因为有5个单位被char和int

使用了。所以不能再挤进去了,于是另外开辟了一个大单位,把4个小单位放了进入。至此,总共用了2个

大单位,而一个大单位是8个小单位,也就是8个字节,所以最终的结果是8*2=16字节。
      
        2.嗯,我们还有另一种方法来理解,这种理解起来要难得多。
          我们可以把结构体内的成员当作一个个的乘客,人人都想到第一个位置,也就是在内存中的首

位置。但是这个位置只有第一个成员才可以拿到。我们可以把他所在的位置与头位置的差叫做“偏移量”

。当偏移量是本身所占字节的倍数的时候,就不用填补。而不是的时候,就要填补到是自身的倍数,并且

自身要占8个字节。
         char a;//此时偏移量为0,是1的倍数。此时所占大小为1
         int b;//此时偏移量为1,因为前面的char所占了一个字节。1不是4的倍数,所以要加3,以变

成4,成为4的倍数,并且b本身也占了8个字节(可以当成运气不好的惩罚吧,呵呵),那么此时又占了

3+8个字节。总占11个字节。
         long c;//此时偏移量为1+11=12。12是4的倍数,所以无需另加单位。此时又占了4个字节。总

占4+11+1个字节,也就是16个字节。

         说了这么多。其实两种方法也就是一个方法。当判断偏移量是否为自身大小的倍数的时候,其

实就是在判断“是否还能够挤进一个大单位”中。当全部判断完后。空的大小(也就是对齐的大小)是一

样的。

 

 

摘自:http://www.hack4.com/article/hack4-21692.html

抱歉!评论已关闭.