在调试程序时,有一个参数需要在多个函数之间传递,因为是作为调试参数,不想将参数引入到函数中。

很自然的想到使用全局变量来表示这个公共参数,工程代码的结构如下:

main.c test.c test.h

main.c和test.c中均调用了test.h文件

全局变量 g_tag

新建一个pubparamter.h文件:

内容如下:

#ifndef _PUBPARAMTER_H_

#defien _PUBPARAMTER_H_

int g_tag;

#endif

之后在文件main.c和test.c文件中,编译发现,g_tag多重定义了,这是因为

加入#include "pubparamter.h"两个c语言在包含pubparamter.h是,对于全局的g_tag定义了两次,导致重定义了。

解决方案1

利用C语言的extern关键字。

extern是C/C++语言中表明函数和全局变量的作用范围的关键字,

该关键字告诉编译器,其申明的函数和变量可以在本模块或其他模块中使用。

在main.c中定义全局变量int g_tag;

在test.c中声明,extern int g_tag;

这个声明表示g_tag为一个外部文件的局部变量,这里只是声明,并非定义。

注意c语言中,声明和定义变量的区别:

声明---表示在文件中可以使用这个变量,但不分配存储空间;

定义---表示在文件中可以使用这个变量,需要分配存储空间。

解决方案2

修改pubparamter.h文件:

内容如下:

#ifndef _PUBPARAMTER_H_

#defien _PUBPARAMTER_H_

extern int g_tag;

#endif

这样在main.c和test.c模块中编译会找不到变量g_tag,但是在链接时会找到。

之后在main.c和test.c中包含就不会多重定义。

扩展 extern "C"的用法

在一些C++头文件中经常或看到这种写法:

#ifndef __INCvxWorksh /*防止该头文件被重复引用*/

#define __INCvxWorksh

#ifdef __cplusplus             //告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的

extern "C"{

#endif

/*…*/

#ifdef __cplusplus

}

#endif

#endif /*end of __INCvxWorksh*/

主要原因是:C++支持函数的重载,C语言不支持函数的重载

如函数

void add(int x,  int y)

void add(int x, float y)

c++ 编译为 _add_int_int  _add_int _float, 这种方式包含了函数名和函数的参数,因而能够区分重载函数

而C中编译为_add函数,这样两个函数都就重复了,报错。

现在假设你要在c++文件中调用C语言的函数,按照c++的编译方式,会将add函数编译为_add_int_int,然而在

c文件模块找不到_add_int_int 函数,因为C语言编译为_add.

可以举一个简单的例子来说明未加extern "C"声明时的链接方式:

//模块A头文件 moduleA.h

#idndef _MODULE_A_H

#define _MODULE_A_H

int foo(int x, int y);

#endif

在模块B中调用该函数:

//模块B实现文件 moduleB.cpp

#include"moduleA.h"

foo(2,3);

实际上,在链接阶段,连接器会从模块A生成的目标文件moduleA.obj中找_foo_int_int这样的符号!!!

显然这是不可能找到的,因为foo()函数被编译成了_foo的符号,因此会出现链接错误。

在实际的工程需求中,由于很多原来的库都是用C语言写的,c++调用C的模块就很平常了,extern "C"就是用来解决这一

工程需求的,指定部分代码按C语言的格式进行编译,而不是C++的,这样可以调用C模块了。、

上面例子的正确解决方案:

moduleA、moduleB两个模块,B调用A中的代码,其中A是用C语言实现的,而B是利用C++实现的,下面给出一种实现方法:

//moduleA头文件

#ifndef __MODULE_A_H //对于模块A来说,这个宏是为了防止头文件的重复引用

#define __MODULE_A_H

int fun(int, int);

#endif

//moduleA实现文件moduleA.C //模块A的实现部分并没有改变

#include"moduleA"

int fun(int a, int b)

{

return a+b;

}

//moduleB头文件

#idndef __MODULE_B_H //很明显这一部分也是为了防止重复引用

#define __MODULE_B_H

#ifdef __cplusplus //而这一部分就是告诉编译器,如果定义了__cplusplus(即如果是cpp文件, extern "C"{ //因为cpp文件默认定义了该宏),则采用C语言方式进行编译

#include"moduleA.h"

#endif

… //其他代码

#ifdef __cplusplus

}

#endif

#endif

//moduleB实现文件 moduleB.cpp //B模块的实现也没有改变,只是头文件的设计变化了

#include"moduleB.h"

int main()

{

cout<<fun(2,3)<<endl;

}

参考:http://www.cnblogs.com/rollenholt/archive/2012/03/20/2409046.html

参考:http://blog.csdn.net/jiqiren007/article/details/5933599

解决全局变量共享---C语言的extern关键字用法的更多相关文章

  1. C++中extern关键字用法小结

    总结C++中关于extern关键字的用法. 1.变量的生明和定义中 C++语言支持分离式编译机制,该机制允许将程序分割为若干个文件,每个文件可被独立编译.为了将程序分为许多文件,则需要在文件中共享代码 ...

  2. c语言之extern关键字

    1.定义 extern,外面的.外来的意思.那它有什么作用呢?举个例子:假设你在大街上看到一个黑皮肤绿眼睛红头发的美女(外星人?)或者帅哥.你的第一反应就是这人不是国产的. extern就相当于他们的 ...

  3. C语言中的extern关键字用法

    在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”. 1. extern修饰变量的声明.举例来说,如果文件a.c需要引用b.c中变量int v ...

  4. cpp extern 关键字用法

    语法说明: extern 可以置于变量或者函数前,以标示变量或者函数的在别的文件中定义,提示编译器遇到此变量和函数后,在其他模块中寻找其定义.此外extern也可用来进行链接指定. 即 extern ...

  5. C语言:static关键字用法

    参考博客:https://blog.csdn.net/guotianqing/article/details/79828100 看个例子: #include <stdio.h> void ...

  6. C语言:const关键字用法

    参考博客:https://www.cnblogs.com/bianchengzhuji/p/10335837.html const是constant的简写,是不变的意思.但并不是说它修饰常量,而是说它 ...

  7. 关于全局变量和函数,在其他类中调用问题,extern关键字

    1个工程下有几个类文件,和1个全局的文件comm.h, comm.h中存放了这几个类同时需要的变量和同时调用的函数. 当时,我只在comm.h中定义: int  commData1: vector&l ...

  8. 【C语言】20-static和extern关键字2-对变量的作用

    一.在Java中,全局变量的定义没有严格的位置规定 全局变量可以定义在类的最前面,也可以定义在类的最尾端,也就说一个方法可以访问在它之后定义的变量. 可以看到,第4行定义的test方法可以访问第8行定 ...

  9. 【转载】理解C语言中的关键字extern

    原文:理解C语言中的关键字extern 最近写了一段C程序,编译时出现变量重复定义的错误,自己查看没发现错误.使用Google发现,自己对extern理解不透彻,我搜到了这篇文章,写得不错.我拙劣的翻 ...

随机推荐

  1. lists删除

    List<Map<String, Object>> trackList = bizFollowRepo.findList("trackFindPageList&quo ...

  2. Mathematics:Pseudoprime numbers(POJ 3641)

     强伪素数 题目大意:利用费马定理找出强伪素数(就是本身是合数,但是满足费马定理的那些Carmichael Numbers) 很简单的一题,连费马小定理都不用要,不过就是要用暴力判断素数的方法先确定是 ...

  3. linux下QT Creator常见错误及解决办法

    最近因为在做一个关于linux下计算机取证的小项目,需要写一个图形界面,所以想到了用QT来写,选用了linux下的集成开发环境QT Creator5.5.1,但刚刚安装好,竟然连一个"hel ...

  4. html中的alt和title用法区别

    html中的alt和title用法区别 首先明确一下概念,alt是html标签的属性,而title既是html标签,又是html属性.title标签这个不用多说,网页的标题就是写在<title& ...

  5. javascript 中 filter 方法

    filter 方法用来迭代一个数组,并且按给出的条件过滤出符合的元素. filter 方法传入一个回调函数,这个回调函数会携带一个参数,参数为当前迭代的项(我们叫它 val ). 回调函数返回 tru ...

  6. 【leetcode】Rotate List(middle)

    Given a list, rotate the list to the right by k places, where k is non-negative. For example:Given 1 ...

  7. 在某公司时的java开发环境配置文档

    1 开发环境配置 1.1.  MyEclipse 配置 1.MyEclipse下载地址:\\server\共享文件\backup\MyEclipse9.0 2.修改工作空间编码为UTF-8,如下图 3 ...

  8. Hibernate 所有缓存机制详解

    hibernate提供的一级缓存 hibernate是一个线程对应一个session,一个线程可以看成一个用户.也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和 ...

  9. Struts2防止表单重复提交

    1.说明 系统拦截器的应用. 表单重复提交:当使用请求转化进行跳转的时候,存在着表单重复提交的问题. 2.在表单中加入s:token 如果页面加入了struts2的标签,页面的请求必须进入struts ...

  10. openssl/asn1.h file not found的解决方法

    iOS 引入支付宝 缺少 #include <openssl/asn1.h>  报错     解决方法: 在 Building Settings -> Search Paths -& ...