C++

extern "C"的作用

C/C++编译的区别

Posted by bbkgl on August 15, 2020

鹿门月照开烟树

忽到庞公栖隐处

目前我直到 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;
}

否则会出现找不到符号的情况。