C++ 与 C 由于基础语法以及数据结构相似,并且 C++ 还是兼容 C 的,在实际开发中经常混在一起用,虽然不像和其他语言混在一起用麻烦,但还是有一些小坑需要注意的。

1. C / C++ 符号区别

C 程序编译后目标文件符号表中的名称和源码中的函数名称是一模一样的,但是 C++ 由于支持函数重载、命名空间等特性,所以 C++ 程序在编译过程中就会用到 name mangling,编译生成的目标文件符号表的名称会在源码中函数名称上面加上一些东西用以区分。所以在混合编程的时候如果不做任何处理即使可以编译通过大概率也是链接不上的。这里可以做一个简单的实验,分别用 C 和 C++ 写一个简单的 Demo,然后用 nm 命令查看他们生成的符号表。

1.1 C 程序符号表

#include <stdio.h>

void sayHello()
{
    printf("Hello World\n");
}

int main()
{
    sayHello();

    return 0;
}

在编译之后可以用 nm 来查看符号表

0000000000001163 T main
0000000000001149 T sayHello

这里删除了一些东西只留下了 mainsayHello 两个函数的符号,可以看到符号表中的名词和程序中的名称是一样的。

1.2 C++ 程序符号表

和上面 C 一样用 C++ 写一个简单的 Hello World

#include <iostream>


void sayHello()
{
    std::cout << "Hello World" << std::endl;
}    


int main()
{
    sayHello();

    return 0;
}

同样的使用 nm 来查看符号表

00000000000011df T main
00000000000011a9 T _Z8sayHellov
                 U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4
                 U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@GLIBCXX_3.4

可以看到 main 函数比较特殊,但是 sayHello 就和程序中定义的不一样了,前面和后面都加了一些东西。所以此时 C 直接连接 C++ 程序的符号的时候会找不到导致链接失败。

2. C++ 调用 C

C++ 在语言设计之初就考虑到了兼容 C 语言语法,所以使用 C++ 来调用 C 还是相对比较简单的是,一般只需要把被引用 C 代码的头文件放着 extern C 里面即可。例如在 main.cc 中可以通过下面这种方法来使用用 C 写的 sayHello.h

extern C
{
    #include "sayHello.h"
}

还有一种比较常见的方法就是直接在 C 的头文件中通过宏来判断是否加上 extern C,例如在用 C 写的 sayHello.h 中就可以这样:

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif

3. C 调用 C++

使用 C 调用 C++ 函数,需要先将 C++ 函数改成 C 风格的,不要用 class和template,一般需要专门写一个适配层。然后在需要被 C 语言调用的头文件中加上 extern C