Skip to content

Language linkage

Mix C and C++

本节标题的含义是: Use C in C++、Use C++ in C

C++的设计目标之一是要兼容C,C++继承了非常C的大部分内容,所以大多数情况下C++是可以兼容C的,比如:

1) C、C++都是基于header file、source file的

2) ......

但是随着语言的发展,两门语言出现了一些分歧,这在C-and-C++\VS-C-VS-C++中进行了讨论。

本文讨论的主题是: 如何在这两门语言相互使用,这大概就是本文的标题Language linkage,跨语言进行link的含义。

Use C in C++

本节讨论在C++中使用C的情况,前面我们已经介绍了: 大多数情况下C++是可以兼容C的,但是对于一些特殊情况,则需要进行特殊处理,这是本节重点关注的内容。

Use C function in C++

extern "C" ?

C++的name mangling(参见C-and-C++\From-source-code-to-exec\ABI\Name-mangling)导致在C++中无法使用C function无法兼容,这就是 extern "C" 所要解决的问题:

对于一个C的header file,通过在**header file**中的function declaration中添加extern "C"的声明,告诉 compiler对于指定的function,不要使用name mangling。这样,当一个C++ compiler编译一个包含这个C header file的C++ source file时候,就不会执行name mangling,这样compiler就能够正确地链接到对应C函数的implementation。这就实现了在C++中使用C的目标。

显然extern "C"就是告诉C++ compiler不要进行name mangling,声明如下:

#ifdef __cplusplus  
extern "C" { 
#endif 
    /* Declarations of this file */
#ifdef __cplusplus 
} 
#endif 

上述声明,能够保证use C function in C++,也能够实现use C++ function in C,这在下一节也会进行介绍。

参见:

1) cnblogs extern “C”的作用详解

这篇文章介绍地还可以。

2) cnblogs extern "C"的用法解析

这篇更好。

3) geeksforgeeks Name Mangling and extern “C” in C++

结合了具体的例子,比较好。

4) stackoverflow Combining C++ and C - how does #ifdef __cplusplus work?

__cplusplus

参见C-and-C++\From-source-code-to-exec\Preprocess章节。

我的实践: 在C++中,使用antirez/sds

这是典型性的在C++中使用C,由于antirez/**sds**的header file中,并没有使用extern "C" {,因此,我第一次在进行编译后,生成的executable有如下错误:

build/main.o:在函数‘getDotfilePath(char*, char*)’中:
util.h:41:对‘sdsnew(char const*)’未定义的引用
util.h:49:对‘sdsempty()’未定义的引用
util.h:49:对‘sdscatprintf(char*, char const*, ...)’未定义的引用
build/main.o:在函数‘freeHintsCallback(void*)’中:
api_shell.h:50:对‘sdsfree(char*)’未定义的引用
build/main.o:在函数‘Command::Command(char const*)’中:
api_app/./../command.h:60:对‘sdssplitargs(char const*, int*)’未定义的引用
build/main.o:在函数‘Command::~Command()’中:
api_app/./../command.h:66:对‘sdsfreesplitres(char**, int)’未定义的引用
build/api_shell.o:在函数‘getDotfilePath(char*, char*)’中:
util.h:41:对‘sdsnew(char const*)’未定义的引用
util.h:49:对‘sdsempty()’未定义的引用
util.h:49:对‘sdscatprintf(char*, char const*, ...)’未定义的引用
build/api_shell.o:在函数‘freeHintsCallback(void*)’中:
api_shell.h:50:对‘sdsfree(char*)’未定义的引用
build/common.o:在函数‘getDotfilePath(char*, char*)’中:
./api_app/../util.h:41:对‘sdsnew(char const*)’未定义的引用
./api_app/../util.h:49:对‘sdsempty()’未定义的引用
./api_app/../util.h:49:对‘sdscatprintf(char*, char const*, ...)’未定义的引用

添加上extern "C" {后,能够正常编译通过。

Use C++ in C

反过来,在C中,可以使用C++吗?这个问题应该是:有些是可以的(比如function),但是有些无法实现的(比如OOP)。由于C++是C的超集,因此当混合使用两者的时候,需要使用g++/gcc --std=c++**来进行编译;

NOTE: 使用g++/gcc --std=c++**来进行编译是我的经验之谈,我参与的项目是这样做的。这样做的原因是: g++/gcc --std=c++**告诉compiler按照C++来进行编译,C++是C的超集。

Use C++ function in C

对于C++中想要暴露给C使用的,需要wrap为C function,并且不能够使用C++的一些特性,比如function overload,并且在function declaration中需要使用extern "C",告诉compiler不要进行name mangling。如果不这样做,则无法实现:

当使用C++ compiler编译带有extern "C"的function的时候,compiler不会进行name mangling;

当使用C compiler进行编译包含了上述function的header file的C source file的时候,C compiler是不会进行name mangling的,这样进行链接的时候,就能够找到function的implementation。

Practice: sqlite extension

我需要写一个sqlite extension,它需要被编译为一个shared library,由于这个shared library需要被dynamic load,因此它没有header file,无法对name mangling进行控制,所以它必须用C来实现。所有的C++,都需要进行wrap。

TODO: embeddedartistry Mixing C and C++: extern C

Examples

本节介绍一些使用了extern "C"的例子:

1) sqlite3.h

2) wikipedia Name mangling

NOTE: 其中也列举了很多案例

cppreference Language linkage

TODO: Namespace and extern

extern “C” linkage inside C++ namespace?

'extern "C"' should not be used with namespaces