当前位置:C++技术网 > 资讯 > C/C++声明定义初始化和赋值独家剖析深刻理解

C/C++声明定义初始化和赋值独家剖析深刻理解

更新时间:2015-06-24 17:57:19浏览次数:1+次

    学了这么久的C/C++,以为对这些基本语法理解很深了。结果今天依然困惑重重,以至于今天始终心里堵得慌。
    这个问题是出在一个大项目的一个静态对象成员变量里的。对于静态成员对象的深刻理解,请阅读本站其他文章,我将后续发表。项目中使用了一个类全局静态锁变量,这个变量是一个对象。而在类声明头文件外,单独进行了对象的定义。程序编译确实可以通过,然而我对此却始终不理解,因而还是要下定决心,细细研究,最后发现是对声明定义和初始化三个概念没有彻底理解。
    我敢说,面试时如果出这么一道题,绝对会考倒绝大多数人。题目就是:“C/C++中的声明定义和初始化有什么区别于联系?”当然,很多人是会答得出来,但是能不能答得清楚,就要看理解到什么程度。简单的答法,教科书都有,三者的区别和联系到底如何,还真不是书上所讲的那样。下面进入正题。
    C语言和C++语言中,这三者其实是一个体系的,并不分家。为什么很多时候我们会觉得C语言中的声明和定义等同呢?在以前学习时,有些老师和课本就是这样讲的,但是为什么等同,其实并没有道破,或许是对于初学者来说,不必知道这么些细节或者一些老师压根本身就不清楚,反正在初学阶段,等同看待就行了。然而曾经的那样的理解却导致很多人现在都不理解为什么,也不会去想为什么,只是知道怎么用就行了。
    要理解三者的关系,我们要看到“内存”、看到“结构体”和看到“类”,如果抛开这三者我们是无法全面理解。
    在C/C++中,数据类型分为两大类,基本类型(内置类型,如int,char等)和自定义类型(结构体,类等)。如果始终把目光聚焦于基本类型,则这三者的概念实在难得分清楚。
    基本类型在声明和定义以及内存分配,是等价理解的,几乎是同时进行的,至少在我们使用时,是可以这么认为的。基本类型是我们使用最频繁的,使用也是最简单的。而自定义类型则需要我们自己来声明类型、定义一个变量,然后初始化一个变量,最后就是使用变量。正是因为自定义类型,我们才有机会深入理解这个过程,而基本类型就把这几个封装了,自动完成,我们就很难观察这些过程。而自定义类型则是需要程序员根据规则构建出来的,这个过程我们都可以把握,从而给我们创造了这个机会。
    对于基本类型,因为整个过程封装在一起,我们就不讨论了。针对自定义类型来理解这三个概念。
    为什么要声明?为什么要定义?对于自定义类型,是由我们程序员自己规定的。而类型在计算机内部则表示为内存占用大小,使用方式等。正是因为是自定义的,编译器就对这个自定义一无所知。你想怎么定义就怎么定义,只要符合编译器给出的规则就行。这是编译器提供给程序员的一个接口,可以让我们自定义。在C语言中就有了,那就是结构体。结构体的大小和内存占用情况会因为定义的成员变量类型、个数以及顺序都有关系,而这个内存结构则是一种类型,这种类型对于编译器本身是不存在的,是我们程序员外部定义的。但是程序要使用这种类型,我们就需要让编译器知道这种类型的情况,占用多少内存空间,在内存中是如何排列的,怎么对齐的,等等。对应在结构体,就是成员变量的个数、类型、排列顺序和对齐方式决定大小。就是我们如何放置结构体内部的成员。具体的参考《关于成员对齐方式》和《结构体对齐问题分析》。
    而此时,我们通知编译器,我们定义的类型是哪样的,就是通过声明类型告诉编译器的。此时的声明就只是告诉编译器,我们自定义的类型是哪样的结构而已,把类型的全部信息告诉编译器。这样编译器就记录下了我们自定义的类型的信息,编译程序时就会用上。如果声明的规则与规定不一致则报错,叫做声明类型错误。
    有了声明类型后,我们就拥有了和基本类型一样的类型可以使用了。做了声明类型这一步后,结构体类型和int类型其实就是同一个层次的,属于同类东西,并没有什么大不了的。就好比,一个农村户口的人通过大量的努力转入了城市户口,最后这个农村户口的人也就变成了城市人口,与其他的城市人口的人属于一样的,所有服务同等对待,谁也不会管,这个人户口是怎么转到城市的。
    然后就是定义变量。在此,我特别提醒一下,声明只是用来声明类型的,定义只是定义变量的,定义是用已有的类型来定义一个变量,使一个变量具备哪种类型。所以,之前我们叫的声明变量和定义类型其实是错误的叫法,这也是为什么大家都错误的理解的根本原因。声明只是告诉编译器我定义了一个类型,对于基本类型来说,不存在声明的说法。不知道你清楚了没有。而定义只是用已经有的类型,基本类型或者你声明好的类型来确定一个变量而已。没有定义一个类型的说法。在这里,“声明"和"定义"是专业术语,有特定的含义,而不可使用汉语的意义去理解为近义词,否则就无法挣脱了。
    而定义一个变量,则是使用定义好的类型来申请分配一个内存块,然后编译器将此内存块与定义的变量符号即变量名映射起来。而这个类型则是对内存分配起决定性作用的,这就是之前声明时提到的内存的空间的问题。如果你不实现声明自定义的类型,编译器在定义变量时无法确定变量应该分配的大小,而基本类型则是内置的,类型所占用的内存大小和分布方式都是内置的,因此就不用声明基本类型,直接使用内置类型定义变量即可。这也是为什么学习C语言时大家听说的声明和定义等同,其实是打错特错,不知道你现在懂了没有。
    初始化,则是对已经分配好的内存即对应的变量符号进行写数据。这里谈谈赋值。有时候赋值和初始化也是浑然不清的。赋值和初始化本质上是一个东西,都是对定义好的变量即对应的内存块写入数据。只不过,初始化是赋值的特例,初始化是指定义好变量即分配好变量的动作完成后立即写入数据。int a = 3;这样就定义了变量a并且立即写入了一个数据。这样就代表完成了初始化。而int a; a=3;这样是执行了两条语句,在计算机内部则是产生了两条指令,分两次执行,而初始化则只是一条指令就解决了。这就是初始化和定义变量后赋值的区别。是不是立即赋值就是初始化,看的是这两个动作在不在一条语句中完成,而不是看两个语句挨着有多近。
    所以,我们那么就都一直在误解这几个基本的概念,就连现在老师还在错误的教。一开始就教错,等日后自己去纠正是很难的,多少都有先入为主的影响。不要以初学者不懂的借口避开这个问题的讲解,这样一解释我相信初学者理解的更加透彻,一开始学就不会疑惑。