C与C++混合编程

一、C与C++混合编程的原理

首先,我先了解一下编译的过程。分为四步:预处理(预处理用于将所有的#include头文件以及宏定义替换成其真正的内容)——编译(将经过预处理之后的程序转换成特定汇编代码(assembly code)的过程)——汇编(汇编过程将上一步的汇编代码转换成机器码)——链接(链接过程将多个目标文以及所需的库文件(.so等)链接成最终的可执行文件).

可以看下原文,大致了解一下:https://www.cnblogs.com/carpenterlee/p/5994681.html

在这里,就不过多分析编译原理,把重心放在如何实现C与C++混合编程的问题上。

我们知道,C语言的发展快五十年了,它积累很多优秀的项目和库,丢弃了很可惜,重写也没必要,那就研究如何在C++中调用它。

C++调用C语言的原理是什么?

其实,C++的编译和C语言是一样的,都要经过四步。前四步是对文件单独处理,而最后一步(链接)则是全员处理。

混合编程的”混合“操作发生在链接这一步。

c++链接时候,能够找到对应的c语言函数的符号,那就意味着实现了混合编程。

二、存在的难点

先摆出结论:

C++编译后,函数的符号会加上前后缀(与形参的类型有关),这样做的好处是可以实现函数的多态(即根据你输入的形参类型来调用相应的函数)。

而C语言编译后,妥妥地一个没有加工的函数名。

所以,要解决的问题是,如何让C++成功链接上(或者对应上,又或者找得上)C语言的符号。

 

测试一:c++ 同名的函数编译,然后反汇编查看符号表。

#include <iostream>

int add(int a, int b)
{
	
	return (a + b);
}

double add(double a, double b)
{
	
	return (a + b);
}

 

测试二:C语言编译

int add(int a, int b)
{
	return (a + b);
}

 

三、解决方案

使用extern "C" {} ,让C++兼容C语言。这个是C++特有的符号,为了让编译器遵循C语言规则。

测试:

extern "C"
{
	
int add(int a, int b)
{
	
	return (a + b);
}

}

编译出.o文件:g++ test.cpp -c -o test.o

反汇编输出:objdump test.o -d > test.i

结果:

用g++编译输出的符号与C语言一样。

这样,就解决了符号的问题。

四、混合编程实验

实验一:同一个项目全部有源码,一次编译链接

//test.cpp

#include <iostream>
#include "clib.h"

using namespace std;
int main()
{
	int result;
	
	result = add(1.1,2.0);
	
	cout << "result: " << result << endl;
	
	return 0;
}
//clib.c

#include "clib.h"

int add(int a, int b)
{
	return (a + b);
}
//clib.h

#ifndef __MYLIB_H
#define __MYLIB_H

#ifdef __cplusplus        //g++编译器会定义这个宏,而gcc没有
extern "C"
{
#endif

int add(int a, int b);



#ifdef __cplusplus
}
#endif


#endif

实现同一个项目全部有源码,一次编译链接的方式是

g++ test.cpp clib.c clib.h -o test

这样的编译肯定没问题,但存在一个大问题:c文件被当作c++源码来编译了(因为c++是c的超集),c语言原本的编译高效就没了,况且有时候项目的某些源码就是用c语言来编写,遵循C语言编译规则比较好。

那么怎么处理?

用gcc单独编译 c文件,最后用g++全部链接在一起。

gcc  clib.c  -c  -o  clib.o

g++  test.cpp  clib.o  -o  test 

值得关注的一点是,在很多项目中,我们都能看到.h文件包含以下内容:

#ifdef __cplusplus       
extern "C"
{
#endif

...

#ifdef __cplusplus
}
#endif

这样做,是为了让.h文件在g++编译器中依旧按照C语言的规则来编译,最终链接时候匹配到C库。

 

实验二:同一个项目中C是库,C++是源码,C++调用C

生成一个静态库,这个库是C语言编写的。

ar  r  libclib.a  clib.o

然后,我们用test.cpp去链接libclib.a库。

g++  test.cpp  -lclib -L.  -o  test

编译成功。

成功的原因是,test.cpp里包含的 clib.h文件中包含了 extern "C"。

在这里,再引出一个问题,加入clib.h没有包含 extern "C"呢?

也很好解决,在test.cpp里补上。

#include <iostream>

extern "C"
{
#include "clib.h"
}

using namespace std;
int main()
{
	int result;
	
	result = add(1.1,2.0);
	
	cout << "result: " << result << endl;
	
	return 0;
}

五、最后

c++想要调用c源码,但又是c源码遵循c编译器的规则,则要使用extern "C"。

在这里插入图片描述

 

  • 6
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值