从编译角度看c和c++混合编译

往期地址:

本期主题:
c和c++混合编译



1.回顾编译和链接

参考前面文章的链接,编译与链接 ,我们知道构建一共有4步:

  1. 预编译
  2. 编译
  3. 汇编
  4. 链接

我们常说的编译和链接,实际上编译包括了前面三步,即 预编译、编译和汇编

2.简单例子使用gcc和ld

写一个简单的例子,就是两个文件都是c文件,一个定义了func函数,另外一个main函数去调用func函数;

//func.h
#ifndef __FUNC_H__
#define __FUNC_H__
#include <stdio.h>
void func();
#endif

//func.c
#include "func.h"
void func(void)
{
	printf("C code, hello world!\n");
}

//main_c.c
#include "func.h"

int main(void)
{
	printf("main func\n");
	func();
	return 0;
}

1.gcc

使用gcc来编译和链接,makefile文件如下:

c_comp:
	gcc -c func.c
	gcc -c main_c.c
	gcc -o a.out func.o main_c.o
clean:
	rm *.o a.out
  1. gcc -c 是将xx.c文件生成目标文件,所谓目标文件的定义参考 操作系统系列五——目标文件详解
  2. gcc -o 是将目标文件链接成可执行文件

2.ld存在的问题(//TODO)

前面的例子如果用ld来进行链接,会存在问题:
在这里插入图片描述
问题是提示缺少了 puts 的reference信息,原因:

这是由于我们的函数用到了printf,printf的底层就是puts,printf依赖于libc.so,但是我们用ld链接时并未将libc.so链接进去

3.c和c++混合编译

将上面的例子改为cpp程序来调用c写好的接口:

//func.h
#ifndef __FUNC_H__
#define __FUNC_H__
#include <stdio.h>
void func();
#endif

//func.c
#include "func.h"
void func(void)
{
	printf("C code, hello world!\n");
}

//main.cpp
#include "func.h"

int main(void)
{
	printf("main func\n");
	func();
	return 0;
}

makefile如下:

cpp_comp:
	gcc -c func.c
	g++ -c main.cpp
	g++ -o a.out func.o main.o

编译结果:
在这里插入图片描述
提示找不到func函数,这是为什么呢?

1.使用nm看符号

我们来定位上面的问题,我们将编译生成的目标文件进行符号解析看看,我们使用nm命令,nm命令能够将目标文件中的symbols(即符号信息)都展示出来
nm命令:
在这里插入图片描述看 main.o 以及 func.o的符号信息:
在这里插入图片描述一看就发现了问题, main.o中对func的符号要求和func.o中的符号要求不一致,所以导致找不到func符号信息

原因剖析:

对于cpp代码而言,函数有重载的可能性,所以cpp编译的目标文件中,对于函数符号是会有参数信息的,例如 funcv实际上就是func(void)的意思
这也就意味着,使用 C 和 C++ 进行混合编程时,考虑到对函数名的处理方式不同,势必会造成编译器在程序链接阶段无法找到函数具体的实现,导致链接失败。

2.如何混合编译,extern “C”

c++已经考虑到了这个问题,所以提供了一个 extern “C” 的方案,作用是:

extern “C” 既可以修饰一句 C++ 代码,也可以修饰一段 C++ 代码,它的功能是让编译器以处理 C 语言代码的方式来处理修饰的 C++ 代码

前面我们那个例子,

  • 在main.cpp中包含了func.h头文件,main.cpp会以c++的方式来解析func函数
  • 而func.c中又是以c的方式来解析func函数

因此解决方案就是在func.h文件中添加extern C,告诉main.cpp同样以c的方式来解析func函数

#ifndef __FUNC_H__
#define __FUNC_H__
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif
	void func();
#ifdef __cplusplus
}
#endif

#endif

再次编译测试,能够正常匹配了:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值