声明与定义的区别

什么是声明,什么又是定义?

相信很多人都问过自己或别人这样的问题。今天,我就发表一下我个人的一点小见解,希望对这两者有疑问的童鞋能理清他们的关系。

理解两者的区别之前,你要重新整理一下一些概念:

1.C语言的对象,不管是什么,变量也好,函数也罢,他们都有且只能有一个定义,而声明却不同,理论上,只要你愿意,他们可以有任意多个声明,这就是为什么形如extern xxx xxx;能被同时包含到不同的头文件的原因(因为它是声明啊,彩旗飘飘,你懂的)

2.声明只是告诉编译器说:“喂,编译器老兄啊,我是某某某的影子,你要找到他的话(编译时用到)去别处找啊,我只是他的影子哦”,所以请记住,声明时编译器并不会为声明的对象分配内存(有内存的话就不会是影子了,是吧),而定义时编译器会为定义的对象分配内存。

可能有人会问:那下面这种情况下哪一个是声明哪一个是定义啊???

其实上面两个都是变量i的声明,他们会最终被保留在可执行文件的BSS段,编译器不会为其分配内存,可能又有人会问:“未初始化的全局变量不是都被编译器隐式地初始化为0吗,他们既然被隐式初始化为0,那也应该有相应的内存地址啊,怎么会都是声明呢?”有这样问题的童鞋很好,说明你已经对声明和定义的区别有所掌握了,不过事实是怎样的呢?事实上编译器不会为BSS段的数据(即未初始化的全局变量)分配内存,只是在BSS段上保留相应未初始化全局变量类型和名字的信息,好让系统运行可执行文件时能给未初始化全局变量分配内存并初始化为0。所以呢,现在清楚了吧,未初始化全局变量是在程序执行时才真正被初始化的,故上面两个都是对量i的声明,而且声明的是同一个i(同一个内存地址),虽然说这样写编译器能接受,但是我强烈建议不要这样写,这是C语言的一个灰色地带,这样会给人感觉是两个变量,而其实他们是同一个,这样只会造成没必要的麻烦,也会让你将来维护这个程序时发疯的,如何避免命名冲突呢?对于其他文件不用引用到的全局变量,我们可以在定义全局变量时在类型名前面加上static关键字来避免命名冲突问题。

倘若是下面这种情况呢:

在这种情况下,第一个文件的是定义,第二个文件的是声明,因为缺省情况下int i跟extern int i是一样的(就是说关键字extern可以省略不写),这同样可能误导别人,例如,我们都知道未初始化的全局变量系统执行时会给它初始化为0,如果我们不知道文件2的 int i其实是文件i声明时就有可能出事,我们会认为文件2的i被系统初始化为0,假如我们把自认为是0的i赋值给别的变量就有可能出现意想不到的bug,所以呢,也请不要这样写,即使你自己知道文件2中int i是对文件1中i的声明(但你能保证维护你代码的人知道吗)。

好像还有一种情况:

呵呵,其实这样是错误的,为什么呢,很简单,两个都是定义,所以编译器会抱怨:“喂,我抗议,这样我怎么编译啊,重定义啊你”。

所以呢,为了解决上面种种情况,我们要保证只在一个文件中出现对一个全局变量的定义,其他文件想引用此变量必须加上extern关键字(即使不加也可以,但务必要加上),同样,如果一个全局变量不是定义在文件的开头而是中间的话,在其同文件前面的函数要引用它也同样要遵循此做法,以免造成不必要的麻烦。 好了,现在的你,是否对声明和定义的区别有了稍微深一点的理解了呢?啊,竟然还不懂,没关系没关系,可能是我讲得不够好,欢迎有兴趣的童鞋共同讨论讨论!

此文是我的一点小小的见解,如果错误的地方还请各位大牛指正,万分感激啊。

什么是声明,什么又是定义?

相信很多人都问过自己或别人这样的问题。今天,我就发表一下我个人的一点小见解,希望对这两者有疑问的童鞋能理清他们的关系。

理解两者的区别之前,你要重新整理一下一些概念:

1.C语言的对象,不管是什么,变量也好,函数也罢,他们都有且只能有一个定义,而声明却不同,理论上,只要你愿意,他们可以有任意多个声明,这就是为什么形如extern xxx xxx;能被同时包含到不同的头文件的原因(因为它是声明啊,彩旗飘飘,你懂的)

2.声明只是告诉编译器说:“喂,编译器老兄啊,我是某某某的影子,你要找到他的话(编译时用到)去别处找啊,我只是他的影子哦”,所以请记住,声明时编译器并不会为声明的对象分配内存(有内存的话就不会是影子了,是吧),而定义时编译器会为定义的对象分配内存。

可能有人会问:那下面这种情况下哪一个是声明哪一个是定义啊???

其实上面两个都是变量i的声明,他们会最终被保留在可执行文件的BSS段,编译器不会为其分配内存,可能又有人会问:“未初始化的全局变量不是都被编译器隐式地初始化为0吗,他们既然被隐式初始化为0,那也应该有相应的内存地址啊,怎么会都是声明呢?”有这样问题的童鞋很好,说明你已经对声明和定义的区别有所掌握了,不过事实是怎样的呢?事实上编译器不会为BSS段的数据(即未初始化的全局变量)分配内存,只是在BSS段上保留相应未初始化全局变量类型和名字的信息,好让系统运行可执行文件时能给未初始化全局变量分配内存并初始化为0。所以呢,现在清楚了吧,未初始化全局变量是在程序执行时才真正被初始化的,故上面两个都是对量i的声明,而且声明的是同一个i(同一个内存地址),虽然说这样写编译器能接受,但是我强烈建议不要这样写,这是C语言的一个灰色地带,这样会给人感觉是两个变量,而其实他们是同一个,这样只会造成没必要的麻烦,也会让你将来维护这个程序时发疯的,如何避免命名冲突呢?对于其他文件不用引用到的全局变量,我们可以在定义全局变量时在类型名前面加上static关键字来避免命名冲突问题。

倘若是下面这种情况呢:

在这种情况下,第一个文件的是定义,第二个文件的是声明,因为缺省情况下int i跟extern int i是一样的(就是说关键字extern可以省略不写),这同样可能误导别人,例如,我们都知道未初始化的全局变量系统执行时会给它初始化为0,如果我们不知道文件2的 int i其实是文件i声明时就有可能出事,我们会认为文件2的i被系统初始化为0,假如我们把自认为是0的i赋值给别的变量就有可能出现意想不到的bug,所以呢,也请不要这样写,即使你自己知道文件2中int i是对文件1中i的声明(但你能保证维护你代码的人知道吗)。

好像还有一种情况:

呵呵,其实这样是错误的,为什么呢,很简单,两个都是定义,所以编译器会抱怨:“喂,我抗议,这样我怎么编译啊,重定义啊你”。

所以呢,为了解决上面种种情况,我们要保证只在一个文件中出现对一个全局变量的定义,其他文件想引用此变量必须加上extern关键字(即使不加也可以,但务必要加上),同样,如果一个全局变量不是定义在文件的开头而是中间的话,在其同文件前面的函数要引用它也同样要遵循此做法,以免造成不必要的麻烦。 好了,现在的你,是否对声明和定义的区别有了稍微深一点的理解了呢?啊,竟然还不懂,没关系没关系,可能是我讲得不够好,欢迎有兴趣的童鞋共同讨论讨论!

此文是我的一点小小的见解,如果错误的地方还请各位大牛指正,万分感激啊。


相关文章

  • extern与头文件(h)的区别和联系
  • 用#include可以包含其他头文件中变量.函数的声明,为什么还要extern关键字? 如果我想引用一个全局变量或函数a,我只要直接在源文件中包含#include (xxx.h包含了a的声明)不就可以了么,为什么还要用extern呢?? 这 ...查看


  • infosys面试总结
  • 1. 作用域public,private,protected,以及不写时的区别 区别如下: 作用域 当前类 同一package 子孙类 其他package public √ √ √ √ protected √ √ √ × friendly ...查看


  • 华为面试题 1
  • ①华为笔试题搜集 1.static有什么用途?(请至少说明两种) 1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变. 2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函 ...查看


  • 2017华为校招笔试题
  • 2017华为校招笔试题 1.局部变量能否和全局变量重名 答:能,局部会屏蔽全局.要用全局变量,需要使用"::" 局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量.对于有些编译器 ...查看


  • C++类和对象的定义
  • 类和对象 类的定义 1 类的定义可以分为两部分:说明部分和实现部分.说明部分说明类中包含的数据成员和成员函数,实现部分是对成员函数的定义.类定义的一般格式如下: //类的说明部分 class<类名> { public: < ...查看


  • iOS求职之OC面试题
  • 1.Objective-C的类可以多重继承么?可以采用多个协议么? 答:不可以多重继承,可以采用多个协议. 2.#import和#include的区别是什么?#import 跟 #import""有什么区别? #impo ...查看


  • 虚,纯虚等的概念
  • 1. 析构函数和虚析构函数 如果基类的析构函数是虚的,那么它的派生类的析构函数都是虚的 这将导致:当派生类析构的时候,它的所有的基类的析构函数都将得到调用 否则,只调用派生类的析构函数(这可能导致基类的某些对象没有得到释放) 所以CObje ...查看


  • VHDL语言中的信号.变量与常量异同比较
  • VHDL语言中的信号.变量与常量异同比较 在VHDL中,对象是指用来保持数据的一些客体单元.VHDL中的对象主要有4种:常量(CONSTANT).变量(VARIABLE).信号(SIGNAL)和文件(FILE).本文主要讨论前面三种在实际应 ...查看


  • C/C++#include 机制简述
  • 1.引言 做c/c++编程的对#include指令都不会陌生,绝大多数也都知道如何使用,但我相信仍有人对此是一知半解, C: #include C++: #include 表示包含C/C++标准输入头文件.包含指令不仅仅限于.h头文件,可以 ...查看


热门内容