extern

extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义

下面分变量和函数来说明:
(1) 变量
 extern int a; //声明一个全局变量
 int a; //定义一个全局变量

 extern int a = 0;//定义全局变量并给初值
 int a = 0; //定义全局变量并给初值
上面的四个只有第一个extern int a才是声明,其他的全是定义。
声明可以多次,但是定义只能有一次。

(2) 函数
函数也有声明和定义,但由于函数的声明和定义是有区别的,函数的定义是有函数体的,所以函数的声明和定义都可以将extern省略掉,反正其他文件也是知道这个函数是在其他地方定义的。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*Demo.h*/
#pragma once
#ifndef _DEMO_H_
#define _DEMO_H_

extern int a;
extern int b;
int add(int a, int b);

#endif

--------------------------

/*Demo.cpp*/
#include "Demo.h"
int a = 10;
int b = 20;

int add(int l, int r)
{
return l + r;
}

--------------------------

/*Main.cpp*/
#include "Demo.h"
#include <iostream>
using namespace std;

int main()
{
cout << "a = " << a << ", b = " << b << endl;

int c = add(1, 2);
printf("c = 1 + 2 = %d \n", c);
system("pause");

return 0;
}

输出:

1
2
3
a = 10, b = 20
c = 1 + 2 = 3
请按任意键继续. . .

这样处理之后只需要到用到的地方加入#include”Demo.h”一句即可,方便了这些变量和全局函数的管理。上面例子中的a和b定义在Demo或者Main哪个cpp文件中都行。

extern “C”

extern “C”的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern “C”后,会指示编译器这部分代码按C语言(而不是C++)的方式进行编译。

由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。例如函数void fun(int, int),编译后的可能是_fun_int_int,而C语言没有类似的重载机制,一般是利用函数名来指明编译后的函数名的,对应上面的函数可能会是_fun这样的名字。

这个功能十分有用处,因为在C++出现以前,很多代码都是C语言写的,而且很底层的库也是C语言写的,为了更好的支持原来的C代码和已经写好的C语言库,需要在C++中尽可能的支持C,而extern “C”就是其中的一个策略

这个功能主要用在下面的情况

  1. C++代码调用C语言代码
  2. 在C++的头文件中使用
  3. 在多个人协同开发时,可能有的人比较擅长C语言,而有的人擅长C++,这样的情况下也会有用到

extern对应的关键字是static,static表明变量或者函数只能在本模块中使用,因此,被static修饰的变量或者函数不可能被extern C修饰

  • 被extern “C”修饰的变量和函数是按照C语言方式进行编译和链接的:这点很重要!!!

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//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;
}
extern “C”的使用要点总结:

1,可以是如下的单一语句:

1
extern "C" double sqrt(double);

2,可以是复合语句, 相当于复合语句中的声明都加了extern “C”

1
2
3
4
5
extern "C"
{
double sqrt(double);
int min(int, int);
}

3,可以包含头文件,相当于头文件中的声明都加了extern “C”

1
2
3
4
extern "C"
{
#include <cmath>
}
  • 不可以将extern “C” 添加在函数内部
  • 如果函数有多个声明,可以都加extern “C”, 也可以只出现在第一次声明中,后面的声明会接受第一个链接指示符的规则。
  • 除extern “C”, 还有extern “FORTRAN” 等。(FORTRAN是一种编程语言)

参考链接:

https://www.cnblogs.com/xiangtingshen/p/10980055.html

https://mp.weixin.qq.com/s/OdJkgNOub1F3I-azLhLyWg