extern 关键字的使用 《程序员的自我修养》·笔记

extern关键字的使用

标签(空格分隔):c/c++


  • C++为了与C兼容,C++可以使用关键字extern “C”来声明或者定义一个C符号:

    extern "C"{
        int func(int);
        int var;
    }

      C++会将extern “C”的大括号内的代码当做C语言代码(.c文件)处理,亦即在大括号中C++的名称修饰机制将不起作用,不同的编译器有不同的名称修饰方法:
      1.如果是VC++平台,上述代码中的fun和var会被修饰(名称修饰)为_func和_var;
      2.但是如果是linux下的gcc编译器,前面的_也会被去掉,extern “C”里面的符号就是修饰后符号(为func和var)。
    【补充】gcc编译.c文件,因为是按照c方式编译,所以函数名不变;gcc编译.cpp文件,g++编译.c文件,g++编译.cpp文件,因为是按照c++方式编译,所以函数名才会加上了附加信息。(当前编译器编译出来的目标文件和库文件(目标文件)应该是同样的编译器编译出来的)
    ps:单独声明某个函数或者是变量是C的符号,可以直接

    extern "C" int func(int);
  • extern “C”带来的问题
      我们经常遇到这样的情况:有些头文件声明了一些C语言的函数和变量,但是这个头文件可能被C语言或者是C++语言包含。例如:
      对于函数 void *memset (void *, int, size_t) 而言,如果不使用extern “C”,考虑一以下两种情况:
      1.在C语言程序包含string.h的时候,如果用到了memset这个函数,编译器会进行正确的函数名称修饰_memset(C语言的名称修饰,前面加_),也可以正确的连接到C语言库中的memset符号。
      2.在C++程序中包含了memset函数,编译器编译器会认为这是一个C++函数,函数名就会被修饰为_Z6memsetPvii(C++的名称修饰可自行了解),这样的话,链接器就没办法在C语言的库中找到对应的符号地址。此时就必须使用extern “C”。

  • C与C++的兼容问题的实现
    方法是使用C++的宏__cplusplus

    
    #ifdef __cplusplus
    
    extern "C" {
    
    #endif
    
    // 代码
    
    #ifdef __cplusplus
    
    }
    
    #endif
    

    含义是,如果是C++代码,那么memset会在extern “C”中被声明,如果是C代码就直接声明。

  • 关于extern在函数指针使用情况下的使用举例
    一个例子:
    (1)工程下面 global.h 中

    ...
    typedef void(*xivc_picture_data_t)(img_params *img);
    ...
    extern xivc_picture_data_t decode_image;  // important
    ...

    (2)工程下面 ldecode.c 中

    
    #include "global.h"
    
    ...
    xivc_picture_data_t decode_image;  // important
    ...
    decode_image = picture_decode_mt;
    ...

    (3)工程下面 image.c 中方可使用decode_image

    
    #include "global.h"
    
    ...
    decode_image(img);
    ...
    • 等价如下
      【ldecode.c】

      typedef void(*xivc_picture_data_t)(img_params *img);
      ...
      xivc_picture_data_t decode_image;  // important
      ...
      decode_image = picture_decode_mt;
      ...

      【image.c】

      extern xivc_picture_data_t decode_image;  // important
      ...
      decode_image(img);
      ...
    • 记录
      上述情况下的extern的使用是基本的使用方式
        在头文件中:extern int g_Int; 它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块或其他模块中使用,记住它是一个声明而不是定义!
        比如,在源文件A里定义的函数,在其它源文件里是看不见的(即不能访问)。为了在源文件B里能调用这个函数,应该在B的头部加上一个外部声明:
        extern 函数原型;
        这样,在源文件B里也可以调用那个函数了。注意这里的用词区别:在A里是定义,在B里是声明。一个函数只能(也必须)在一个源文件里被定义,但是可以在其它多个源文件里被声明。定义引起存储分配,是真正产生那个实体。而声明并不引起存储分配。打一个粗俗的比方:在源文件B里声明后,好比在B里开了一扇窗,让它可以看到A里的那个函数。

    • 基本规则
        extern用在变量声明中常常有这样一个作用,你在*.c文件中声明了一个全局的变量,这个全局的变量如果要被引用,就放在*.h中并用extern来声明。

    • 注意
        另外一种方法是在公共的*.h文件中使用全局变量,两个*.c文件同时include该.c文件,就可以避免使用extern,也可以做到函数的更新同步。上述例子中,直接在global.h文件中使用 xivc_picture_data_t decode_image; 即可。但是,上述方法可能会引起重复定义的问题,最好的方法还是使用extern,养成好的习惯

    • 补充
        在一个.c文件的最前面使用extern int f(); 和int f();是等效的,都说明了f函数可能在其他函数中定义,而在当前函数中只是声明一下有待使用。但是最好还是使用extern关键字,避免误解。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值