补遗篇之sizeof

    sizeofC的单目运算符,它给出操作数存储所需的字节数,其操作数可以是表达式或类型名。sizeof()是运算符,不是函数,没有函数调用开销。其结果是在编译阶段由编译器自动给出,相当于常数,不象函数那样在运行时才得到返回值

    sizeof常用来屏蔽同一类型变量在不同平台上占用不同空间的问题,能提高C程序的可移植性。不懂得利用sizeof就出现int *p = malloc(800)

    问:为什么直接分配800字节?  答:因为要分配200个整数的空间

    问:为什么200整数就是800字节?答:因为在XX平台上整数是4字节,200个就是800字节

    问:那其他平台上整数也是4字节么?如果不是怎么办?答:………

    改为int *p=malloc(sizeof(int)*NUM);,所有平台表达形式就一致了,数据类型的平台差异就由编译器通过sizeof屏蔽(不同平台的编译器负责给出正确的sizeof(类型)值)。然而或许由于权限给了编译器,sizeof操作数覆盖面太宽,增加了很多语法花样。其实,知道在哪用sizeof更有实际意义,本来就是编译器自动处理,又何必人为掺和。下面内容适合应付C笔试,很多考官喜欢在这里作文章。

sizeof禁区

sizeof不能用于函数,不完全类型或位字段。不完全类型指存储空间未知的数据类型,如不定长数组、void型等。所以char char_v[]sizeof(char_v)sizeof(void)都不正确。

基本数据类型与指针

    操作数为基本类型或一般变量时,sizeof得到类型或变量bytes,如int16位系统占2bytes32位系统4bytes。操作数是类型须加括弧,变量名可加可不加,如:

    char c;

    sizeof c;//变量名可不加(),同样得到变量类型所占bytes,这里等同于sizeof(char)

    操作数为指针时sizeof得到指针型所占bytes,如32位系统4bytes。但指针牵涉到其所指内存变量的类型,易概念混淆。如:

    int* a//sizeof(a)4,没异议,但不同人所指的4意义不一定相同哦

    char *a; //sizeof(a)多少呢?答1就露馅了,char是谁的类型,sizeof(a)求的又是什么类型,正确答案仍是4。不明白就看看前文指针类型的含义。

数组

    sizeof(数组)得到数组总bytes。结论简单,但前提要确定操作数是否为数组型。如char array[10],不同表达式中,array有时代表类型char [10]的数组;有时仅代表0号元素地址值:

    sizeof(array)中,array代表数组型,sizeof得到数组bytes10

    sizeof(*array)中,array是地址,*array是数组0号元素的值。所以sizeof(*array)得到数组单元的byte,即sizeof(char),为1

    sizeof(array+n)中(n=0,1,...),array还是地址,array+n也是地址,所以sizeof(array+n)得到指针大小,相当于sizeof(char *),为4

    此外数组作参数传进函数时,编译器传递数组首地址,所以函数内的sizeof(array)也取指针大小,如:

    int func(char array[10]){     return sizeof(array); //数组参数退化为地址,sizeof(array)=4       }

struct/union

    按理说sizeofstruct大小只需依次累加所有member所占bytessizeofunion则取最大member所占bytes。但如考虑内存对齐限制,情况复杂了。某些平台编译器会"对齐"存放,struct/union对齐可能包括:struct成员变量地址相对struct起始地址的偏移须为该变量自身占用bytes的倍数;struct/union总大小为最大成员所占bytes的倍数。举例:

    struct MyStruct

    {

      double da;

      char ca;

      int ia;

   };

    编译器先为成员da分配空间,占用sizeof(double)=8字节,其起始地址和结构起始地址相同;然后为ca分配空间,这时可分配地址相对结构起始的offset为8,满足sizeof(char)=1倍数,所以ca放在offset 8bytes,自身占1byte;接着ia,此时offset为9,不是sizeof(int)=4的倍数,编译器自动填充3bytes对齐,offset变为12,可被4整除,ia存放在offset12处,占4bytes。至此所有member分配完,总size为8+1+3+4=16,刚好是结构的字节边界(结构中最大变量所占字节数sizeof(double)=8的倍数),不需再填充。所以最终结构大小为16,其中3bytes是编译器自动填充的空白字节。

    交换一下成员变量的位置,变为:

    struct MyStruct

    {

      char ca;

      double da;

      int ia;

    };

    这时分配过程为:ca offset为0,满足对齐,占1byteda初始offset为1,不是sizeof(double)=8的倍数,填充7bytes对齐,保存在offset为8处,自身占8bytesia初始offset为16,是sizeof(int)=4倍数,不需填充,存放在offset为16处,自身占4bytes。至此所有member都分配了空间,总size为1+7+8+4=20。但20不能被dasizeof(double)=8整除,不满足结构边界对齐,需额外填4bytes,(20+4)/8才满足。所以struct最终大小为:1+7+8+4+4=24。其中7+4=11是编译器填充的空白字节。

对于union型,sizeof以其最大成员的字节数为基础,边界对齐填充后得到结果。如不考虑对齐,sizeof a11,如考虑对齐,为16

  union a{

      int r;

      double e;

      char q[11];

    };

    以上structunion内存对齐和sizeof结果,只为说明编译器的处理策略,不同编译器结果可能不同,只要知道有这么回事就行了

    另外:sizeof计算C++结构或类时,静态成员变量不影响结构或类的大小,因为静态变量的存储位置与结构或类的实例地址无关。

strlensizeof

    计算字符串长度的strlensizeof在某些场合易混淆,这里做个对比:

    1sizeof是运算符,编译时由编译器给出结果;strlen是函数,运行中调用后得到结果。

    2sizeof可用类型做操作数,strlen只能用char*型变量做参数,且char*所指内存必须是以'\0'结尾的字符串,不能是字符数组。

    3sizeof得到某类型实际占用内存的大小,而strlen通过遍历到字符串结尾的'\0',得到字符串中的字符总数。如:

    char str[20]="0123456789";

    char* ss = "0123456789";

    int a=strlen(str);          //a=10,运行时计算得字符串长度

   int b=sizeof(str);         //b=20,编译期确定str数组实际占用内存的大小

    int c=sizeof(ss)          //ss是指向字符串的指针,sizeof取指针所占空间,4字节

    int d=sizeof(*ss)        //*ss是字符串第一个字符'0',所占的内存是char型,1字节

    int e=strlen(ss)         //e =10,获取字符串长度,一定要用 strlen

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值