Kyle Chen's Blog

Action speaks louder than Words

0%

C++中的extern关键字

用法一:调用外部变量或者函数

1.调用别的源文件中的全局变量

  • 这里需要注意的是,被引用的变量v的链接属性必须是外链接(external)的,也就是说a.cpp要引用到v,不只是取决于在a.cpp中声明extern int v,还取决于变量v本身是能够被引用到的。

  • 这涉及到c语言的另外一个话题--变量的作用域。能够被其他模块以extern修饰符引用到的变量通常是全局变量

  • 还有很重要的一点是,extern int v可以放在a.cpp中的任何地方,比如你可以在a.cpp中的函数fun定义的开头处声明extern int v,然后就可以引用到变量v了,只不过这样只能在函数fun作用域中引用v罢了,这还是变量作用域的问题。对于这一点来说,很多人使用的时候都心存顾虑。好像extern声明只能用于文件作用域似的。

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    在一个源文件里定义了一个数组:char a[6];
    在另外一个文件里
    用下列语句进行了声明:extern char *a;
    请问,这样可以吗?
    答案与分析:
    1)、不可以,程序运行时会告诉你非法访问。
    原因在于,指向类型T的指针并不等价于类型T的数组。
    extern char *a声明的是一个指针变量而不是字符数组,
    因此与实际的定义不同,从而造成运行时非法访问。
    应该将声明改为extern char a[ ]。

2.调用别的源文件中的函数

  • 全局函数的声明语句中,关键字extern可以省略,因为全局函数默认是extern类型的。

  • 从本质上来讲,变量和函数没有区别。函数名是指向函数二进制块开头处的指针。

  • 如果文件a.cpp需要引用b.cpp中的函数,比如在b.cpp中原型是int fun(int mu),那么就可以在a.cpp中声明extern int fun(int mu),然后就能使用fun来做任何事情。

  • 就像变量的声明一样,extern int fun(int mu)可以放在a.cpp中任何地方,而不一定非要放在a.cpp的文件作用域的范围中。

  • 对其他模块中函数的引用,最常用的方法是包含这些函数声明的头文件。使用extern和包含头文件来引用函数有什么区别呢?extern的引用方式比包含头文件要简洁得多!extern的使用方法是直接了当的,想引用哪个函数就用extern声明哪个函数。

  • 这样做的一个明显的好处是,会加速程序的编译(确切的说是预处理)的过程,节省时间。在大型C程序编译过程中,这种差异是非常明显的。

3.调用别的头文件中的变量/函数

  • 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数。
  • extern int a; 仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。
  • externint a; //属于声明
    externint a = 10; //属于定义
  • 声明可以拷贝n次,但是定义只能定义一次。
  • extern作为声明使用,就是告诉当前编译单元,不要为这个extern修饰的变量分配空间,这个变量已经在别的编译单元分配了空间。
  • extern作为定义使用,用于创建外部变量,也可以认为是全局变量。

用法二:调用C方式的变量或者函数

C方式编译和C++方式编译
相对于C,C++中新增了诸如重载等新特性,对于他们的编译,必然有一些重要的区别。
我们将下面的小程序分别按C和C++方式编译,来探讨两种编译方式的区别。

  • extern “C” 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。

1. Cpp文件调用C文件中的函数

2. Cpp文件调用C文件中的变量

3. Cpp文件调用C方式的头文件

  • 例二
1
2
3
4
5
6
7
8
9
10
11
//Out.h
#ifdef __cplusplus //该段代码引用网上的...,
extern "C"{
#endif

#include <stdio.h>
extern void aa();

#ifdef __cplusplus
}
#endif
1
2
3
4
5
6
//Out.c
#include "Out.h"
void aa()
{
printf("aa is running");
}
1
2
3
4
5
6
7
8
9
//Test.cpp
#include <iostream>
using namespace std;
#include "Out.h"
int main()
{
aa();
return 0;
}

例三