相信使用微软编译器的大家(例如vs2017)肯定会遇到这样的一个问题,说你的某个变量重复定义,就像这个样子。
具体可能是代号为LNK2005和LNK1169。这个错误可能会出现在你是第一次开始使用多文件来编写程序。现在,我们就来探讨一哈这个问题。首先来介绍几个概念。
在C Primer Plus 一书中,在第12章 存储类,链接和内存管理中,有链接这样一个概念。
具有代码块作用域和函数原型作用域的变量具有空链接。这意味着它们是由其定义所在的代码块或函数原型所私有的。
具有文件作用域的变量可能就有空链接或者外部链接。
一个具有外部链接的变量可以在一个多文件程序中被使用,而一个具有内部链接的变量可以在一个文件中任何地方使用
至于什么时具有文件作用域,代码块作用域,大家不懂的话就自己去查一下,这里就不多讲了。
回归正题,为什么大家程序编译后会出现重复定义捏?你可能之前还看到过说你在你的文件加上几行这样的代码就好了:
#ifndef _STATEMENT_H
#define _STATEMENT_H
...
...
#endif
但是你会发现你可能加上去还是没有解决问题!所以,在这里你就的好好了解一哈这个原因了。
大家产生这个问题的原因可能会和我的不一样,但是你可听一哈我的分析,再去看看自己的代码。原因就在于我自己想要定义一个全局变量,但是把它定义到我的.h文件中去了(因为我当时是想说,反正以后别的文件包含这个.h文件,就可以使用该变量了。)但是,也就是因为这样,编译报错了。原因就是我没有遵守“.h就只要声明,不要定义”规矩。你可以去把你要定义的全局变量放在.c文件中定义,而.h文件中使用extern来申明该变量。总之:你的全局变量定义最好就在.c文件中定义,而他的申明可以放在.h文件中,使用extern 扩展其定义。方便之后其他文件的调用。
上面讲的是解决方法。那之前讲的那个定义有什么用处捏。为了就是解释一个一个问题。举个例子:
在a.c文件中,你有一个全局变量的定义:static int i;
在b.h文件中你也写了extern int i;
然后你想要在main.cpp中通过#include"b.h"来使用变量i。但是你会发现编译就会报错。
原因就是static变量是一个具有内部链接的变量,其作用域只有该文件内部,在这里就是a.c文件中才可以使用。但是extern int i;必须要求其变量具有文件定义域。所以,这里可能会报一个无法解析的外部指令这样一个问题。就是因为这里b.h文件中extern int i;并没有起到声明a.c文件中static int i;变量这样的目的。(以下内容是自己的理解)这里相当于又声明了int i;但是没有给其分配内存,之后你去使用它时,就会报无法解析的外部指令这样的错误。仔细一想,好像之前定义的函数,但是没有具体实现函数,而直接去使用函数的时候,也会报这样的错误。
上面的解释都没有研究其本质,本质还得去看编译器是怎么处理的,这样才能将其完全弄清楚。但是我还没有到可以研究编译器的地步,但是我会继续努力的,加油!
下面的百度百科那篇关于extern 讲解的还是十分好的,可以仔细看看!
参考过的文章,值得去看
https://baike.baidu.com/item/extern/4443005?fr=aladdin
https://zhidao.baidu.com/question/625405489688417844.html?qq-pf-to=pcqq.c2c