extern 可以置于变量或者函数前,以表示这个变量或函数别的文件中定义
,提示编译器在遇到此变量或函数的时候在其他模块寻找其定义。
主要使用方式有两种:
- 如果函数的声明中带有
extern
,说明这个函数定义在其他文件中,这样的好处是可以取代include"**.h"
,在一些复杂的项目中这样使用比较方便。最好的做法是全部函数声明前添加extern
. extern "C"
支持C/C++混合编译
1. 全局变量在.cpp
中定义,在.h
中extern
声明
如果没有extern
,对于 int a;
和int a = 0;
,即是定义也是声明
但是有了ertern
以后
extern int a;//声明全局变量a,只是声明,且这个全局变量已经被声明&定义过
int a; //声明&定义全局变量a
extern int a =0 ;//声明&定义全局变量a 并给初值。
int a =0;//声明&定义全局变量a,并给初值,
1.1 首先来看在.h中声明并定义的问题: 导致编译冲突
#ifndef __TEST1_H
#define __TEST1_H
extern char g_str[] = "123456"; // 声明&定义全局变量g_str
void fun1();
#endif
#include "test1.h"
void fun1() { cout << g_str << endl; }
然后test2.cpp
也需要这个全局变量,就需要在源文件中include <test1.h>
但这样会报连接错误,这是因为你把全局变量g_str
的定义放在了头文件之后,test1.cpp
这个模块包含了test1.h
所以定义了一次g_str
,而test2.cpp
也包含了test1.h所以再一次定义了g_str
,这个时候连接器在连接test1和test2时发现两个g_str
.
解决方法:
在test2.cpp中extern char g_str[];
,而不用include
。
但这时想include <test1.h>
就只能一个个extern了,很麻烦,所以最好在声明时解决这个问题,而不是使用时。方法如下:
1.2 只在.cpp中声明并定义
如果全局变量在test1.cpp
中声明&定义,那么在test2.cpp
中再include
也没用,这时必须在test2.cpp中extern char g_str;
给程序员的建议就是全局变量使用时,对他声明定义&初始化,这通常会在.cpp中声明和定义
1.2 在.cpp中声明并定义,在.h中声明
这是很好的选择.
#ifndef __TEST1_H
#define __TEST1_H
extern char g_str[]; // 声明&定义全局变量g_str
void fun1();
#endif
#include "test1.h"
char g_str[] = "123456"
void fun1() { cout << g_str << endl; }
1.3 总结
- 头文件中声明并定义全局变量,当其他文件include这个文件时,会编译错误
- 实际上用到这个全局变量的地方可能很多,使用时每个文件都需要
include
,所以把声明和定义都放在.cpp
,使用的时候extern
,而不extern
可能也是不错的选择。这时候可以include
也不会报错. - 但全局变量和定义都放在
.h
中绝对不可取.
2. extern函数
3. extern "C"
extern "C" #告诉C++编译器,使用C语言方式编译和链接.
C++为了多态,编译时会将函数名和参数联合生成一个中间函数名
,例如为了支持函数重载,C++会将void foo(int x, int y)
编译为_foo_int_int
之类的名字,C编译后在符号库中的名字则为_foo
,混合编译时二者产生差异。
我们是在main.cpp文件里包含了test.h
,这些函数在main.cpp里,所以会被C++编译一个中间函数名
,而test.c
里面的实现会被C
编译器处理,所以main就找不到test.c
的函数.
这个时候就必须用extren "C"
了,告诉C++
编译器,请使用C语言方式编译和链接.
3.1 C++中引用C的函数变量:方法1(.C中加extern “C”)
我们将test.h里面的东西改一下写法即可:
/*Demo.h*/
#ifndef _DEMO_H_
#define _DEMO_H_
#ifdef __cplusplus//如果在C++中就使用C方式编译,这样就和.c编译方式中一样了
extern "C" {
#endif
extern int a;
extern int b;
int add(int a, int b);
#ifdef __cplusplus
}
#endif
#endif
/*test.c*/
#include "test.h"
#include <stdio.h>
int a = 10;
int b = 20;
int add(int l, int r)
{
/*
#ifndef __cplusplus //C++
printf("这是一个c程序!\n");
#endif
#ifdef __cplusplus //C
printf("这是一个c++程序!\n");
#endif
*/
return l + r;
}
在main函数引用头文件
/*main.cpp*/
#include "Demo.h"
#include <iostream>
using namespace std;
void main()
{
int c = add(1, 2);
printf("c = 1 + 2 = %d \n", c);
system("pause");
}
3.2 C++中引用C的函数变量:方法2(.cpp中加extern “C”)
在包含头文件时添加extern "C"
,告知使用C语言方式编译该头文件,这样也就能和C的源文件保持编译方式一致。
/* c语言头文件:cExample.h */
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
int add(int x, int y);
#endif
/* c语言源文件:cExample.c */
#include "cExample.h"
int add(int x, int y)
{
return x + y;
}
-------------------------------------------------------------
/* C++ main函数,包含cExample.h */
extern "C"
{
#include "cExample.h";
}
//或者extern "C" int add(int x, int y);
int main()
{
add(2, 3);
return 0;
}
3.3 C中引用C++的函数和变量
- 由于 C语言中不支持extern “C”,但
#ifdef __cplusplus
后可以使用 - 所以还得在C++的头文件中给函数声明加上
extern "C"
- C不能直接引用声明了extern “C”的头文件
- 所以不能像3.1那样直接包含头文件,
-
C.cpp
中还必须将C++中定义的extern “C”函数声明为extern类型
/* c++头文件cppExample.h */
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add(int x, int y);
#endif
/* c实现文件cFile.c */
extern int add(int x, int y);
int main()
{
add(2, 3);
return 0;
}