tag 标签: sizeof

相关博文
  • 热度 18
    2013-1-24 15:56
    2164 次阅读|
    1 个评论
    第一篇的学习笔记整理,一直在想应该从哪开始说起,仔细归纳下发现,其实软件学习最重要和最频繁的就是跟内存打交道了,所以决定先说一说内存。 曾经在一本大牛的著作里看到说,软件设计中绝大部分的bug都来自于程序员对代码中内存的使用不清楚而出现的“误操作”。而我觉得,高手与新手的区别就在于是否对程序所使用硬件资源的了如指掌了。 言归正传,我们要揭秘内存,我选择从sizeof说起(对它的重新认识让我觉得学校所讲的那些个编程课我都白听了…必须得好好弄清楚才行)。 首先,sizeof是一个运算符?对,是的,它不是函数,而是一个单目运算符。更严格的说,它是编译运算符,也就是说,在编译器编译时,它便得出了运算结果(也就是我们想知道的数据类型或变量所占用的内存空间)。 下面就来举例说明它的应用了,也许其中会有让你大吃一惊的地方。 1、各基础类型大小; 这个相对简单,字符型char为1个字节,其它的int、float、double等根据不同的编译环境而有所不同。如下图,博主在VS2010,win7-64bit环境下编译的结果。此处有两点需要说明,有的编译器会将‘*’这样的字符常量分配2个字节的大小,原因很简单,就是在末尾加入了一个‘\0’;还有一点就是我们可以看到,一个浮点常数是被默认当做double型来处理的。   2、数组及指针; 直接先给出结果,如下图代码及结果。对于字符数组,需要注意‘/0’的添加,这常常会让我们忽略这个字节。而对于其它类型的数组则不会添加任何数据。指针类型的大小则更加依据程序的编译环境,这里需要注意的是,如本例中,虽然所使用的操作系统为64位的win7,但我们在VS2010中选用的编译环境仍然是Win32,所以此处指针类型的大小(也就是内存地址的大小)仍然是32位,4个字节。还有一点需要说明,sizeof运算符可以用于void的指针,却不能用于void类型,因为void属于不完全类型,即具有未知内存大小的数据类型,同样的还有:函数类型、未知大小的数组类型、未知内容的结构或联合类型等。   3、结构体及联合体类型; 先来说明下结构体和联合体,结构体是将几个数据类型的变量结合起来形成一个整体,其中每个变量都是这个结构体的一个属性,都会被分配到相应的内存。而联合体,则是指几个数据类型的变量共用一片内存空间,只是名称指代不一样。有一个最好理解的例子:需要得到一个既可bit复制又可字节赋值的字节,先将八个bit型定义成一个字节的结构体,然后将这个结构体和一个char型定义为一个联合体,这样便可以达到我们的目的了。 两者的区别理解了以后,我们再来看sizeof运算两者的结果。对于联合体,得到的其所最大字节成员的大小,这个在了解了联合体的作用便很容易明白了,为了满足所有成员的使用,必须给它分配最大的那个成员的内存了。那我们便自然会觉得,对于结构体,不就是所有成员变量所占用空间的大小之和么?如下图的程序和结果,会发现,并不是这样的!而且都比我们预想的要大。这是为什么??简单来说,这是编译器对内存分配采用的对齐方式。 下面我们细说下这种对齐方式。在给结构体分配内存时,按照定义的顺序依次对变量进行分配,从第二个变量开始,就需要对地址进行对齐,我们的对齐数就是已经分配过的变量和正要分配变量中字节数最大的类型的大小,我们定义为N,则当我们每分配一个变量时,会得到一个对齐数,然后根据这个对齐数和上一个变量首字节地址A,来获得我们要分配变量的首字节地址B,如果(A+N)能被N整除则B=A+N,如不能则B往后移至可以整除为止。如本程序例子,对于st3这个结构体,c0分配到地址2095528;n分配时,对齐数N=4,n的地址为2095532,在c0后面则插入了三个空字节;c分配时,对齐数仍为4,才的地址为2095536,;d分配时,对齐数N变成了8,则需在c后面插入7个空字节,d的地址为2095544;c1分配时,同理,c1地址为2095552,但需在其后面再插入7个空字节来对齐,这样st3共占用32个字节,地址从2095528到2095560。(为什么编译器需要这样来做呢?下回详解) 另外还需要注意的是,对于结构体中的静态变量,sizeof是不计算它所占用的空间的,因为静态变量统一被分配与静态内存区,与结构体无关。而且,空的结构体也是需要占用1个字节大小的,因为每一个结构体实例都必须在内存中占有独一无二的地址。 4、在函数中,数组等做形参时; 这样的情况我们需要把握一点,数组做形参时,函数调用实际传递的是地址。如下面的例子,得到的结果正是说明函数所传递的只是数组的首地址而已,把数组当做指针来用。 还有种情况,如果是函数做形参呢??其实,还是传递的地址,只不过是代码的地址。 5、sizeof与strlen的对比; 对于字符串的长度计算我们常常用strlen,需要注意的是它是一个函数,而不是运算符。其函数原型如下图。可见,它会在遇到0x00时返回。 对于上例中的s5,我们使用strlen计算得到的是21,为什么呢?而且,为什么我们输出s5这个字符串时显示的是“123456烫烫烫烫烫Hello”,这里面的“Hello”显然是我们s4中定义的那个“Hello”吧?这又是怎么回事呢?(同样的,下回详解)  
  • 热度 20
    2012-7-31 18:01
    1787 次阅读|
    0 个评论
    Sizeof与Strlen的区别与联系 一、sizeof     sizeof(...)是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。     它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。     由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。实际上,用sizeof来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。     具体而言,当参数分别如下时,sizeof返回的值表示的含义如下:     数组——编译时分配的数组空间大小;     指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为4);     类型——该类型所占的空间大小;     对象——对象的实际占用空间大小;     函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。 ************** 二、strlen     strlen(...)是函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组就退化成指针了。     它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符NULL。返回的长度大小不包括NULL。 ***************** 三、举例:     eg1、char arr = "What?";               int len_one = strlen(arr);               int len_two = sizeof(arr);               cout len_one " and " len_two endl;     输出结果为:5 and 10     点评:sizeof返回定义arr数组时,编译器为其分配的数组空间大小,不关心里面存了多少数据。strlen只关心存储的数据内容,不关心空间的大小和类型。     eg2、char * parr = new char ;               int len_one = strlen(parr);               int len_two = sizeof(parr);               int len_three = sizeof(*parr);               cout len_one " and " len_two " and " len_three endl;     输出结果:23 and 4 and 1     点评:第一个输出结果23实际上每次运行可能不一样,这取决于parr里面存了什么(从parr 开始知道遇到第一个NULL结束);第二个结果实际上本意是想计算parr所指向的动态内存空间的大小,但是事与愿违,sizeof认为parr是个字符指针,因此返回的是该指针所占的空间(指针的存储用的是长整型,所以为4);第三个结果,由于*parr所代表的是parr所指的地址空间存放的字符,所以长度为1。 ************ 四、参考资料: Sizeof与Strlen的区别与联系(转) 1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。 该类型保证能容纳实现所建立的最大对象的字节大小。 2.sizeof是算符,strlen是函数。 3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。 sizeof还可以用函数做参数,比如: short f(); printf("%d\n", sizeof(f())); 输出的结果是sizeof(short),即2。 4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。 5.大部分编译程序 在编译的时候就把sizeof计算过了 是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因 char str ="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 ) fun(char memcpy(buf, p1, len); } 我们能常在用到 sizeof 和 strlen 的时候,通常是计算字符串数组的长度 看了上面的详细解释,发现两者的使用还是有区别的,从这个例子可以看得很清楚: char str ="0123456789"; int a=strlen(str); //a=10; strlen 计算字符串的长度,以结束符 0x00 为字符串结束。 int b=sizeof(str); //而b=20; sizeof 计算的则是分配的数组 str 所占的内存空间的大小,不受里面存储的内容改变。 上面是对静态数组处理的结果,如果是对指针,结果就不一样了 char* ss = "0123456789"; sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针,sizeof 获得的是一个指针的之所占的空间,应该是 长整型的,所以是4 sizeof(*ss) 结果 1 ===》*ss是第一个字符 其实就是获得了字符串的第一位'0' 所占的内存空间,是char类 型的,占了 1 位 strlen(ss)= 10 如果要获得这个字符串的长度,则一定要使用 strlen
相关资源