C语言:如何区分 声明与定义

C语言:如何区分 声明与定义,第1张

变量声明变量定义

变量定义:用于为变量分配存储空间,还可为变量指定初始值。程序中,变量有且仅有一个定义。

变量声明:用于向程序表明变量的类型和名字。

定义也是声明,extern声明不是定义

定义也是声明:当定义变量时我们声明了它的类型和名字。

extern声明不是定义:通过使用extern关键字声明变量名而不定义它。 

[注意] 

变量在使用前就要被定义或者声明。 

在一个程序中,变量只能定义一次,却可以声明多次。 

定义分配存储空间,而声明不会。

  C++程序通常由许多文件组成,为了让多个文件访问相同的变量,C++区分了声明和定义。

   变量的定义(definition)用于为变量分配存储空间,还可以为变量指定初始值。在程序中,变量有且仅有一个定义。

   声明(declaration)用于向程序表明变量的类型和名字。定义也是声明:当定义变量的时候我们声明了它的类型和名字。可以通过使用extern声明变量名而不定义它。不定义变量的声明包括对象名、对象类型和对象类型前的关键字extern。

   extern声明不是定义,也不分配存储空间。事实上它只是说明变量定义在程序的其他地方。程序中变量可以声明多次,但只能定义一次。

   只有当声明也是定义时,声明才可以有初始化式,因为只有定义才分配存储空间。初始化式必须要有存储空间来进行初始化。如果声明有初始化式,那么它可被当作是定义,即使声明标记为extern。

   任何在多文件中使用的变量都需要有与定义分离的声明。在这种情况下,一个文件含有变量的定义,使用该变量的其他文件则包含该变量的声明(而不是定义)。

现在来讨论一下定义和声明的区别。

C++primer的解释是这样的:

变量的定义(definition):用于为变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且仅有一个定义;

变量的声明(declaration):用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字。可以通过使用extern关键字声明变量名而不定义它。

以上解释讲得还是比较清楚的,有分配空间的叫定义,没分配空间的叫声明。好吧,你不知道什么时候分配什么时候没分配。让我们换一种说法。

“定义也是声明”,这说明声明包括定义。所以诸如int aextern int a之类的一定是声明。那是不是定义还要接着往下看;

如果程序前面都没有出现过a这个变量,这时你要使用a,你必须让程序知道你要使用a这个变量了。这时候你写入int a以前没有a这个变量的,现在程序为了记住它,就得为他分配空间,于是这是个定义。

如果程序包含的其他文件里已经出现过a了,这证明程序已经为a分配内存,这时你要使用a就方便很多了。你只需要告诉程序,这个a在其他地方定义过了,于是你写入extern int a

对于int a来说,它既是定义又是声明;对于extern int a来说,它是声明不是定义。一般为了叙述方便,把建立存储空间的声明称定义,而不把建立存储空间的声明称为声明.

[引申阅读]探讨下c++的声明和定义问题,关于extern

c++primer第四版中,53页的习题2.18中问到,extern std::string name是属于声明还是定义?答案说的是声明。不过我认为,string类中有默认构造函数,如果该语句在函数外,那么则会自动获得储存空间,将name定义为空字符串,不知各位有何高见?

问题补充:

感谢回答我的关于extern的问题,可是还是没想通。正如一楼举的例子extern std:tring name("Zhang3Li4")我认为extern std::string name和那句是一样的 .因为标准库中的string是有默认构造函数的,若后面什么都没有的话,就初始为空字符串

------

我刚才做了一个实验:

//a.cpp

#include <string>

std::string i

//b.cpp

#include <iostream>

#include <string>

extern std::string i

int main ()

{

std::cout <<i <<std::endl

}

运行结果为:

(上面是一空行:由于末尾用了endl)

如果没有a.cpp这个文件,运行出错

这是一对实验(有没有a.cpp文件)

可得出这样的结论:

a.cpp中std::string i是定义(本来就是)

b.cpp中extern std::string i则是声明(你的问题)

先别急,这只是实验结果。我们还需要理论依据,那么下面就试着解释一下:

下面是另一个例子(也是第二个实验)

你应该知道内置类型(int等)如果作为全局变量时,定义的同时也就初始化了(一个内置类型有其对应的默认值;如果你将自定义类型也看成内置类型,那么就等于说,一个自定义类型有其对应的默认值(由默认构造函数完成))。如

//c.cpp

int i

//d.cpp

#include <iostream>

extern int i

int main ()

{

std::cout <<i <<std::endl

}

那么在这里int i就是定义(并且初始化了i,初始值为0)

因而输出结果为

0

//这个实验的运行结果符合理论依据。

(我使用的编译器是visual studio 2008)

从这两个实验来看:(将两个“默认”等同起来)

int i

std::string i

都可以作为初始化i的定义性语句。

那么

extern int i

extern std::string i

也具有定义行为(这个很明显与extern的用法相悖)

在以上两个试验中:int 与 string 有“区别”吗?所有的代码都一样只不过把std::string 换成了 int而已!如果你能解释int的情况,那么我想std::string问题也就迎刃而解了!

于是我个人总结出一个结论:

不论是内置类型还是自定义类型,前面有extern关键字,如果没有显式地初始化参数(即就是自定义类型的默认构造函数被extern屏蔽了,不起初始化的作用),那么就按声明对待。

可能我的描述很混乱,希望你好好看看上面的例子,就明白了!

注意:从这里可以看出来默认构造函数的特殊性!


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8147158.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-13
下一篇 2023-04-13

发表评论

登录后才能评论

评论列表(0条)

保存