在 C 语言中, extern 关键字具有外延性,使修饰的变量作用域可以拓展到其他文件中。而在C 中,extren被重载后有了其他功能,就是修饰函数以什么方式进行编译。决定了在编译过程中是否对函数进行倾轧(Name Mangling)操作,也是在今天才知道倾轧这个词语。
在C 中增加了函数重载操作,也就是可以在源代码中编写同名函数,调用者根据填写实参的不同,匹配不同的函数实现执行对应的操作,这个过程称作函数重载。而真正在编译后,函数名字并不是我们想象中真的一模一样,而是C 编译器在内部对函数名进行了倾轧操作,将相同函数名而不同形参的函数利用某些固定规则进行了改名操作,调用过程中不会因为函数名个冲突而导致出现错误,实际我们在编写源代码过程中C 这门语言只是为了给我们提供一个方便的编程环境,而并非真的使用了相同的函数名。那么具体在倾轧以后函数名变成了什么样子呢? 为了分析这个问题,我们首先要想办法看到在编译后的程序内部,函数名是什么样子的。而普通的执行文件好像是没有什么方法可以看到,至少目前我还不清楚,但是我们可以通过dll导出函数的方式,来看看C 编译的dll 和 C 编译出来的dll 到底有什么差别。 查看dll导出函数的工具:Dependency Walker
代码语言:javascript复制#include <stdio.h>
// 使用 C 编译器编译后的dll导出函数不会倾轧
_declspec(dllexport) int add(int a, int b)
{
return a b;
}
_declspec(dllexport) int sub(int a, int b)
{
return a - b;
}
代码语言:javascript复制#include
// 使用 C 编译器编译后的dll导出的所有函数都会倾轧
_declspec(dllexport) int add(int a, int b)
{
return a b;
}
_declspec(dllexport) int sub(int a, int b)
{
return a - b;
}
如果想让C 编译器不对函数进行倾轧,可以使用 extern “C” 关键字,让其使用C语言的方式导出函数。
代码语言:javascript复制#include
// 使用 C 编译器编译后的dll导出的所有函数都会倾轧
// 增加 extern “C” 关键字
extern “C” {
_declspec(dllexport) int add(int a, int b)
{
return a b;
}
_declspec(dllexport) int sub(int a, int b)
{
return a - b;
}
}
如果想让编写出来的代码既可以在C下编译,又可以在C 下编译。可以增加一个判断,如果是C 文件就增加extern “C” 关键字,如果不是就不加,这样就可以非常灵活的使用 extren “C” 关键字了。实现如下:
代码语言:javascript复制#include
// 使用 C 编译器编译后的dll导出的所有函数都会倾轧
// 增加 extern “C” 关键字
#ifdef __cplusplus
extern “C” {
#endif
_declspec(dllexport) int add(int a, int b)
{
return a b;
}
_declspec(dllexport) int sub(int a, int b)
{
return a - b;
}
#ifdef __cplusplus
}
#endif