鹿门月照开烟树
忽到庞公栖隐处
目前我直到 extern "C"
的作用就是告诉C++编译器在生成符号的时候按照C的风格生成。
普遍用在两个方面:
- C++函数声明时,使用
extern "C"
可以让C也能调用到这个函数 - C++调用部分C函数时,使用
extern "C"
包裹include
能够成功链接到对应的C函数
第一个用法常常用在C++需要编写某些库函数给C#/Lua/Python/Java调用的时候,这个是很常见的。
第二个用法则是C++调C库的时候。。。这里疑问来了,我们写C++调用很多C库函数/系统调用的时候也没用这个 extern "C"
包裹 include
呀?不也照样能跑。。。glibc/libssl都是用C写的呀。
查了很多资料,都是说C++调C库的时候要用这个 extern "C"
包裹 include
。。。可是不这么做通常也没事呀。
这里我暂时猜测一下原因,首先从C++的理论设计上来说,几乎是全面兼容C的,如果说调用个C库还得extern "C"
包裹 include
,显然不符合全面兼容C的设计理念。
我猜测C++在链接某个库找符号时,并不是只找C++风格的符号,应该也会同时找C的,找到其中一个就进行链接。
所以大部分C++调C的场合,应该是不需要用这个 extern "C"
包裹 include
的。
从我的记忆来讲,需要这么用的情况应该是项目中既有.c,又有.cpp文件,同时某些调用了C函数的C++代码又可会被当成库在其他情况下调用。
最典型的场景就是,使用C++写一个给Lua用的库,编译成动态库so文件。
这个时候,是一定需要 extern "C"
包裹 include
的,大概像下面这样子。
#include <iostream>
#include <cstdio>
extern "C" {
#include "lua.h"
#include <lauxlib.h>
#include <lualib.h>
}
extern "C" int add(lua_State *L) {
double d1 = luaL_checknumber(L, 1);
double d2 = luaL_checknumber(L, 2);
lua_pushnumber(L, d1 + d2);
return 1;
}
extern "C" int luaopen_test(lua_State *L) {
luaL_Reg luaLoadFun[] = {
{"add", add},
{NULL, NULL}
};
luaL_newlib(L, luaLoadFun);
return 1;
}
否则会出现找不到符号的情况。