IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    c关键字-sizeof的种种

    sponge发表于 2010-11-14 07:02:48
    love 0

    熟悉c的人都知道,sizeof是一个关键字而不是一个宏或者库函数什么的,他的值是在编译时确定的,如果这个不了解,可以现看看这篇文章和这篇文章。 既然如此,让我们先看下面几个小例子:

    sizeof(int);
    sizeof(char);
    sizeof(double);

    上面三行sizeof的值是多少呢?这里我们假定在32位的x86系统下。我们会得到答案:4,1,8。这个没什么吧,大多数人都应该知道。那么,下面这个:

    sizeof(int);
    sizeof(long);

    在32位x86下,这两个是多少呢?4,8?

    实际上,答案是4,4。我们需要注意,long类型在32位系统下是32位的。那么,64位下结果又如何呢?8,8?其实答案是4,8。另一个需要注意的是,64位下的int是32位的。

    上面只是热热身,现在,让我们看sizeof的下面几种情形:

    1、sizeof一个结构体。

    这个我就不说啥了,具体的参考这篇文章。至于空的结构体,下面会解释。

    2、sizeof数组、指针等 先看下面两个例子:

    char a[100];
    char b[100]="helloworld!";
    char c[]="helloworld!";
    char* d=b;
    sizeof(a);
    sizeof(b);
    sizeof(c);
    sizeof(d);

    在32位x86系统下,以上各是多少呢?

    答案是:100,100,12,4。

    为什么不是100,12,12,12呢? sizeof一个数组名,返回的是数组的大小,不管你数组里面放的什么数据。所以,第一个数组大小是100,第二个数组大小是100,第三个数组大小是12(别忘记"\0")。第四个呢?第四个不是一个数组名,而是一个指针!32位下指针大小永远是4,不管你是指向一个数组还是一个int还是一个char。 好,这个问题搞清楚之后,看下面这个程序:

    int func(char a[100])
    {
        printf("%d\n", sizeof(a));
    }
    int main()
    {
        char *m = "helloworld!";
        func(m);
        char n[100]="helloworld!";
        func(n);
    }

    这个程序会打印出什么结果呢?

    答案是:4, 4。 为什么结果都是4?不是应该返回数组长度么?

    这里出现又一个需要注意的地方:在作为参数传递的时候,数组名会退化为指针。也就是说,这里的func里的参数,虽然看上去是个数组名,但实际上还是个指针。 你了解了么?下面是几个练习,自己实验下^_^

    char *p = NULL;
    sizeof(p);
    sizeof(*p);
     
    int a[100];
    sizeof(a);
    sizeof(a[100]);
    sizeof(&a);
    sizeof(&a[0]);

    懒得实验?答案分别是4,1,400,4,4,4。为什么?自己想想。

    3、sizeof一些诡异的东西

    (enum,空类,空struct) 所谓的诡异的东西,就是一些你想到的想不到的东西拿来sizeof。比如说sizeof一个enum类型是多少?一个空struct呢?一个空类呢? 这些诡异的东西在标准C中都没有作出规定,很大程度上都是编译器和系统结构相关的。 先来看一个:

    int main()
    {
        enum week{Mon, Tue, Wed, Thu, Fri, Sat, Sun};
        printf("%d\n", sizeof(enum week));
    }

    这个你会得到什么样的结果呢?28? 在gcc或者vc下运行一把,你会得到答案:4。

    为什么呢? 实际上,enum具体有多大取决于编译器的实现,目前大多数的编译器都将其实现为int类型。也就是说这里的enum被当作int类型(当然,使用上不一样)。这不是一成不变的,有些编译器,如VC++允许下面这种定义:

    //注意这是个cpp文件
    enum Color : unsigned char
    {
       red, green, blue
    };
    // assert(sizeof(Color) == 1);

    enum先说到这里,那么一个空的结构体是多大呢? 如果你擅长C语言,你可以很快的写出下面的程序:

    //this is a *.c file
    struct node{
     
    }Node;
    int main
    {
        printf("%d\n", sizeof(Node));
    }

    很快,你可以验证出来结果是0。 没错,这很好理解。但是,如果你用的是c++呢?

    //this is a *.cpp file
    struct node{
     
    }Node;
     
    class node2{
     
    }Node2;
     
    int main()
    {
        printf("%d\n", sizeof(Node));
        printf("%d\n", sizeof(Node2));
    }

    (不怎么会写c++的我表示压力很大)以上这个c++的例子结果是多少呢?

    为什么会得到1,1这个结果呢? 换句话说就是为什么sizeof一个空类和空结构体在c++下就是1呢?

    这个原因要追朔到c++标准中的一句话:“no object shall have the same address in memory as any other variable”, 用中国话简单点说就是:不同的对象之间应该有不同的地址(为什么会有这样的规定?看这里)。

    既然每个对象都必须有不同的地址,让我们假设上面代码中的Node的size是0,想想会出现什么样的后果?

    Node a;
    Node b;

    a的大小是0,b的大小是0,那么,a和b的地址是不是很可能重复了?

    所以,为了保证不同的对象拥有不同的地址,最简单的方法就是保证所有类型的大小都不是0。

    所以,为了保证这点,大多数c++编译器都会给空结构或类加上一个冗余的字节保证类型不为空。

    我的解释的清楚么?如果我的表达能力不够好,看这里,解释的足够详细。 当然,还有其他很多我没有想到的诡异的东西可以拿来sizeof,如果你想到了,欢迎跟我分享。至于c++中的sizeof类,基类,派生类,足够可以作为一个专门的文章了,先不再这里说,等我学会C++的再写一下相关内容(-_-")。

    最后,给一个稍微给力点的程序,大家看看最终得到的结果是什么(注意这是一个c++程序):

    //this is a cpp file
    typedef   struct   weekday_st
    {
            enum   week     {sun=123456789,mon,tue,wed,thu,fri,sat,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak};
            enum   day{monring,   moon,   aftermoon};
    }weekday_st;
     
    int   main(int   argc,   char   *argv[])
    {
            printf( "sizeof(weekday_st)=%d\n ",   sizeof(weekday_st));
            printf( "sizeof(weekday)=%d\n ",   sizeof(weekday_st::week));
            printf( "sizeof(day)=%d\n ",   sizeof(weekday_st::day));
            return  0;
    }

    参考书目:《C专家编程》 《C语言深度解剖:解开程序员面试笔试的秘密 》



沪ICP备19023445号-2号
友情链接