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

15 篇文章 0 订阅

原文来自http://blog.sina.com.cn/s/blog_65db99840100kvm8.html

对于一个char*类型的数据,sizeof的结果包括末尾的\0,strlen不包括。这一点很实用

sizeof部分转自http://www.vckbase.com/document/viewdoc/?id=1054

最近在论坛里总有人问关于sizeof的问题,并且本人对这个问题也一直没有得到很好的解决,索性今天对它来个较为详细的总结,同时结合strlen进行比较,如果能对大家有点点帮助,这是我最大的欣慰了。

一、好首先看看sizeof和strlen在MSDN上的定义:

首先看一MSDN上如何对sizeof进行定义的:

sizeof Operator sizeof expression The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t. The expression is either an identifier or a type-cast expression_r(a type specifier enclosed in parentheses). When applied to a structure type or variable, sizeof returns the actual size, which may include padding bytes inserted for alignment. When applied to a statically dimensioned array, sizeof returns the size of the entire array. The sizeof operator cannot return the size of dynamically allocated arrays or external arrays.

然后再看一下对strlen是如何定义的:

strlen Get the length of a string. Routine Required Header: strlen <string.h> size_t strlen( const char *string ); Parameter string:Null-terminated string Libraries All versions of the C run-time libraries. Return Value Each of these functions returns the number of characters in string, excluding the terminal NULL. No return value is reserved to indicate an error. Remarks Each of these functions returns the number of characters in string, not including the terminating null character. wcslen is a wide-character version of strlen; the argument of wcslen is a wide-character string. wcslen and strlen behave identically otherwise.

二、由几个例子说开去。

第一个例子:

char* ss = "0123456789"; sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针 注:这里ss是指针,32位机中占4byte,64位机中占8byte 
sizeof(*ss) 结果 1 ===》*ss是第一个字符
 char ss[] = "0123456789"; sizeof(ss) 结果 11 ===》ss是数组,计算到\0位置,因此是10+1 注:这里是ss数组,不是指针,还要注意最末尾的'\0'。如果这样定义一个char数组char ss[10] = "0123456789";编译不通过,数组界限溢出。
ADDED20101028 
这里牵涉到一个问题,就是char*和char数组真的是等价的吗?我的博文《char、char*、char**数组》里讲的其实并不准确,大部分情况下可以把char数组名当做char*指针来处理,但有的时候还是不同的。可以参考http://blog.csdn.net/dog250/archive/2010/02/09/5303372.aspx 也可以总结为“
数组做sizeof的参数不退化,传递给strlen就退化为指针了。
sizeof(*ss) 结果 1 ===》*ss是第一个字符
 char ss[100] = "0123456789"; sizeof(ss) 结果是100 ===》ss表示在内存中的大小 100×1
 strlen(ss) 结果是10 ===》strlen是个函数,内部实现是用一个循环计算到\0之前为止 
注意 int ss[100] = "0123456789"; sizeof(ss) 结果 400 ===》ss表示在内存中的大小 100×4 
strlen(ss) 错误 ===》strlen的参数只能是char* 且必须是以''\0''结尾的 char q[]="abc"; char p[]="a\n"; sizeof(q),sizeof(p),strlen(q),strlen(p); 结果是 4 3 3 2

第二个例子:

class X { int i; int j; char k; }; X x; cout<<sizeof(X)<<endl; 结果 12 ===》内存补齐
cout<<sizeof(x)<<endl; 结果 12 同上

第三个例子:

char szPath[MAX_PATH]

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

第四个例子:
string s;

sizeof(s)的值是32,因为string类的实现是一个char*指针,然后还有保存长度等信息的成员,加起来就是32个字节。

三、sizeof深入理解。

  • 1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
  • 2.sizeof是算符,strlen是函数。
  • 3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。sizeof还可以用函数做参数,比如:
    short mmax(){return 1;} printf("%d\n", sizeof(mmax()));
    输出的结果是sizeof(short),即2。
  • 但是sizeof(mmax) 则编译报错
  • .sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式 这个明显不对,MAX未定义的话,怎么可能编译通过呢
  • 4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
  • 5.大部分编译程序 在编译的时候就把sizeof计算过了是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因
    char str[20]="0123456789"; int a=strlen(str); //a=10;
     int b=sizeof(str); //而b=20;
  • 6.strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。
  • 7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
  • 8.当适用了于一个结构类型时或变量, sizeof 返回实际的大小, 当适用一静态地空间数组, sizeof 归还全部数组的尺寸。 sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
  • 9.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如:
    fun(char [8]) fun(char [])
    都等价于 fun(char *) 在C++里传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小如果想在函数内知道数组的大小,需要这样做:进入函数后用memcpy拷贝出来,长度由另一个形参传进去
    fun(unsiged char *p1, int len) { unsigned char* buf = new unsigned char[len+1];  memcpy(buf, p1, len); 
    } 有关内容见: C++ PRIMER?
  • 10.计算结构变量的大小就必须讨论数据对齐问题。为了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

 

设置为1、2的时候都好理解,设置为4的时候为什么不是12呢?因为编译器按顺序为成员变量分配内存,char+short总共3byte,还不到4byte,补齐为4byte即可,再加4byteint,总共8byte

四、结束语

sizeof使用场合。

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

讲到sizeof,顺便把C的数据类型贴出来,免得忘记

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值