C/C++混合编程时extern "C"的使用

本文详细探讨了在C/C++混合编程时extern "C"的使用,解释了其作为链接指示的作用,如何在C调用C++函数以及C++调用C函数。文章通过实例展示了如何在头文件中使用extern "C"声明函数,以避免命名倾轧问题,确保正确链接。

我们在遇到规模较大的项目时候,常常会有C\C++混用的情况,某些功能模块用C语言来实现,而另外一些则用C++。当模块之间相互提供接口供对方使用的时候,必然会看到extern "C"这个字样。那么,这篇文章就来探讨下extern "C"的作用以及使用方法。为了便于更直观的理解,全程都会使用例子的形式来描述。

1 extern "C"是啥

首先,extern "C"它是一个链接指示,一方面,在C++语言需要调用C语言写的函数的时候,该函数也必须要在C++中进行声明;另一方面,在C语言写的函数中需要调用C++实现的接口时也一样。
一个函数的声明,包括该函数的名称、返回类型以及形参列表等,并且必须与函数的定义完全匹配。我们知道,C++语言是支持函数重载的,例如下面两个函数,他们名称、返回类型相同,但形参列表不同:

int Func(int a) {
   
    //... }
int Func(double b) {
   
    //... }

同样的事情,在C中就不可以,编译器在编译的时候会报错。这是因为C++为了支持重载而使用了命名倾轧的方法,也就是说编译C++文件的时候,最终生成的函数签名不仅仅跟函数的名称有关,也跟函数的返回值和形参列表有关。例如,查看上述代码生成的.o文件,可以看到有如下两个函数签名,也就是说,命名相同的两个函数,一个实际的签名为_Z4Funci,另一个是_Z4Funcd。

Disassembly of section .text:

0000000000000000 <_Z4Funci>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d fc                mov    %edi,-0x4(%rbp)
   7:   5d                      pop    %rbp
   8:   c3                      retq

0000000000000009 <_Z4Funcd>:
   9:   55                      push   %rbp
   a:   48 89 e5                mov    %rsp,%rbp
   d:   f2 0f 11 45 f8          movsd  %xmm0,-0x8(%rbp)
  12:   5d                      pop    %rbp
  13:   c3                      retq

有了以上基本概念后,下面就来讲讲extern "C"的作用,以及如何在C/C++中相互调用函数。

2 C调C++函数

首先来看下C调C++函数的方法。假设我们当前有如下3个文件:CppSrcFile.cpp、Common.h、CSrcFile.c。这是一种很常见的实现方式,在.cpp文件中写函数的实现,以.h的形式对外提供接口,.c通过包含提供的.h文件来调用接口。

/* CppSrcFile.cpp */

int FuncInCppSrcFile(int a) {
   
   }
/* CommonApi.h */

int FuncInCppSrcFile(int a);
/* CSrcFile.c*/

#include "CommonApi.h"

void FuncInCSrcFile()
{
   
   
    int rstl = FuncInCppSrcFile(1);
}

int main()
{
   
   
    FuncInCSrcFile();
}

然而, 当我们编译上面两个源文件的时候,编译器就会报符号找不到的错误:

moocos-> gcc CppSrcFile.cpp CSrcFile.c
/tmp/ccfSWy70.o: In function `FuncInCSrcFile':
CSrcFile.c:(.text+0xe): undefined reference to `FuncInCppSrcFile'
collect2: error: ld returned 1 exit status

我们先后退一步,使用gcc -c命令,分别生成两个.o文件,然后再用objdump查看它们的函数签名以及符号表。可以看到,.c文件生成的.o文件,符号表中UND项以及调用的C++的函数接口命名依然为FuncInCppSrcFile,而.cpp生成的.o文件中对应的函数被命名为FuncInCppSrcFile。因此,链接器在链接的时候,找不到FuncInCppSrcFile这个符号。

moocos-> objdump -dtr CSrcFile.o

CSrcFile.o:     file format elf64-x86-64

SYMBOL TABLE
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值