zoukankan      html  css  js  c++  java
  • 解决全局变量共享---C语言的extern关键字用法

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

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

    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

  • 相关阅读:
    自动登录网站
    爬取梨视频
    爬虫介绍,request模块和代理ip
    数据结构与算法
    CMDB的总结
    自动化运维模块
    linux命令补充
    centos7的目录结构,文件系统常用的命令,vim编辑器
    linux配置网卡文件,xshell链接服务,快照,克隆,修改主机名
    flask的请求扩展,错误处理,标签和过滤器,中间件以及cbv的写法
  • 原文地址:https://www.cnblogs.com/adong7639/p/4157212.html
Copyright © 2011-2022 走看看