- extern ˈekstɜ n外面的;外来的;对外的
当extern与"C"在一起修饰变量或函数时
- C++ 与 C 编译区别
在C++中常在头文件见到extern "C"修饰函数,那有什么作用呢? 是用于C++链接在C语言模块中定义的函数。
C++虽然兼容C,但C++文件中函数编译后生成的符号与C语言生成的不同。因为C++支持函数重载,C++函数编译后生成的符号带有函数参数类型的信息,而C则没有。
例如 int add(int a, int b)
函数经过C++编译器生成.o文件后,add会变成形如 add_int_int
之类的, 而C的话则会是形如 _add
, 就是说:相同的函数,在C和C++中,编译后生成的符号不同。
这就导致一个问题:如果C++中使用C语言实现的函数,在编译链接的时候,会出错,提示找不到对应的符号。此时extern "C"就起作用了:告诉链接器去寻找_add这类的C语言符号,而不是经过C++修饰的符号。
- 被 extern “C” 修饰的变量和函数是按照 C 语言方式编译和连接的
- extern “C” 的作用是让 C++ 编译器将 extern “C” 声明的代码当作 C 语言代码处理,可以避免 C++ 因符号修饰导致代码不能和C语言库中的符号进行链接的问题。
#ifdef __cplusplus
extern "C" {
#endif
void *memset(void *, int, size_t);
#ifdef __cplusplus
}
#endif
在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明
,在.c文件中包含了extern "C"时会出现编译语法错误。所以使用extern "C"全部都放在于cpp程序相关文件或其头文件中。不过与C++调用C接口不同,C++确实是能够调用编译好的C函数,而这里C调用C++,不过是把C++代码当成C代码编译后调用而已。也就是说,C并不能直接调用C++库函数。
extern int add(...)
int add(){
}
extern "C" {
#include "xx.h"
}
extern "C"{
int add();
}
int add(){
}
extern int add();
作用域扩展
-
当 extern 不与"C"在一起修饰变量或函数时,如在头文件中:extern int g_Int;
它的作用就是声明函数或全局变量的作用范围的关键字
,其声明的函数和变量可以在本模块或其他模块中使用,记住它是一个 声明不是定义
也就是说编译单元B要是引用编译单元A中定义的全局变量或函数时
,它只要包含A的头文件即可,在编译阶段,模块B虽然找不到该函数或变量,但它不会报错,它会在链接时从模块A生成的目标代码中找到此函数。
-
注意:在使用extern时候要严格对应声明时的格式
,比如在一个源文件里定义了一个数组:char a[6];,在另外一个文件里用下列语句进行了声明:extern char *a;这样是不可以的。但这同时也就造成另一个问题:如果函数原型被单方面修改的话,调用方在不知情情况下进行调用,在编译阶段不会报错
,但是在运行时会由于参数类型不匹配而出错,所以现在大多只在头文件中进行声明并使用#include头文件的方式来引入函数而非extern。
-
extern的常用用法:在源文件中声明了一个全局的变量,这个全局的变量如果要被引用,就放在头文件中并用extern来声明。
-
作用域扩展用法:
#pragma once
#include <iostream>
int _g_o = 100;
void _g_fun() {
std::cout << "Hello, World!" << std::endl;
_g_o = 999;
}
#include <iostream>
#include "externTest.h"
extern int _g_o;
extern void _g_fun();
int main() {
std::cout << "_g_o: "<< _g_o << std::endl;
_g_fun();
std::cout << "_g_o: "<< _g_o << std::endl;
return 0;
}