第一篇的学习笔记整理,一直在想应该从哪开始说起,仔细归纳下发现,其实软件学习最重要和最频繁的就是跟内存打交道了,所以决定先说一说内存。
曾经在一本大牛的著作里看到说,软件设计中绝大部分的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”吧?这又是怎么回事呢?(同样的,下回详解)
用户593939 2013-1-28 22:57