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

这篇具有很好参考价值的文章主要介绍了从编译角度看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来进行链接,会存在问题:
从编译角度看c和c++混合编译
问题是提示缺少了 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

编译结果:
从编译角度看c和c++混合编译
提示找不到func函数,这是为什么呢?

1.使用nm看符号

我们来定位上面的问题,我们将编译生成的目标文件进行符号解析看看,我们使用nm命令,nm命令能够将目标文件中的symbols(即符号信息)都展示出来
nm命令:
从编译角度看c和c++混合编译看 main.o 以及 func.o的符号信息:
从编译角度看c和c++混合编译一看就发现了问题, 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

再次编译测试,能够正常匹配了:
从编译角度看c和c++混合编译文章来源地址https://www.toymoban.com/news/detail-408347.html

到了这里,关于从编译角度看c和c++混合编译的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【操作系统-内存】地址翻译流程图

    简略版: 完整版:(注意,TLB和Cache是组相联的) 字节编址 一页为 4KB 逻辑地址空间为 32 位(4GB) 物理地址空间为 28 位(256MB) 页表项长度为 4B TLB为八路组相联,一共16行(组数=16/8=2) Cache为四路组相联,一共16行(组数=16/4=4),Cache行大小为64B 字节编址 一页为 4KB 逻辑

    2024年02月12日
    浏览(46)
  • 操作系统实验6:地址映射与共享

    本次实践项目有两个基本内容: (1)用Bochs调试工具跟踪Linux-0.11的地址转换过程; (2)实现基于共享物理页框的进程间内存共享。 和一个段有关的信息需要 8 个字节来描述,所以称为段描述符(Segment Descriptor),每个段都需要一个描述符。为了存放这些描述符,需要在内

    2023年04月15日
    浏览(72)
  • 凝思操作系统配置IP地址方法

    方法1: /etc/network/interfaces文件中配置: 如上,以此配置所有的eth*,, 测试: 1)未加allow-hotplug eth0     ip不生效; 2)这句可以不加:gateway 193.168.100.1   另外,正如,windows系统一块网卡可以设置多个ip地址, linux系统一块网卡,也可以设置多个ip 注意:第二个ip,没有添加g

    2024年02月12日
    浏览(47)
  • 更改centos7操作系统的IP地址

    如果安装的是有图形化界面,如GUI等图形化界面的话修改起来相对简单,在我的虚拟机克隆中有介绍。但是如果你安装的只有黑窗口的centos7的话,可以采取本文章的方式。 1、输入ip addr命令查看本系统的网卡名称 如下图,我的网卡是ens33 输入以下命令编辑网络配置文件 如我

    2023年04月08日
    浏览(53)
  • 5-Linux操作系统 vi/vim编译器

    一、vi编译器介绍   Vi编辑器是所有Unix及Linux系统下标准的编辑器,类似于windows系统下的notepad(记事本)编辑器,由于在Unix及Linux系统的任何版本,Vi编辑器是完全相同的,因 此可以在其他任何介绍vi的地方都能进一步了解它,Vi也是Linux中最基本的文本编辑器,学会它后,

    2024年02月08日
    浏览(38)
  • 《操作系统导论》吐血万字整理 - 附下载地址及思维导图

    我看的是这本,豆瓣9.4,很经典的教材书, 在文章末尾我附上了网盘链接 这篇博客算是一个完整的读书笔记,我大概读了20天看完的,电子版做笔记很方便,推荐一波,很多课上没有讲到的知识在这本书里都详细阐释了 全书的思维导图 一个正在运行的程序会做:取址执行。

    2023年04月19日
    浏览(39)
  • 【操作系统基础】【CPU访存原理】:寄存 缓存 内存 外存、内存空间分区、虚拟地址转换、虚拟地址的映射

    存储器怎么存储数据、内存空间分区、虚拟地址转换 计算机的存储器:寄存 缓存 内存 外存(按功能划分) 计算机的处理器需要一个存储器来存储大量的指令和数据以便自己不断取指执行和访问数据。 内存 (内存就是运行内存,如手机的8G运行内存,电脑的16G运行内存)就

    2024年01月25日
    浏览(59)
  • 杭电操作系统实验一 --- Linux内核编译及添加系统调用(arm架构华为云)

    掌握Linux 内核的编译与安装 掌握Linux 系统调用基本概念 设计和添加linux系统调用         (1)修改或返回指定进程的优先级(nice值和prio值)(详见教材P328)提示:可能参考的内核函数:set_user_nice().         (2)改变主机名称为自定义字符串(自选题目)   1、 L

    2023年04月20日
    浏览(44)
  • 从头开发一个RISC-V的操作系统(三)编译与链接

    目标:通过这一个系列课程的学习,开发出一个简易的在RISC-V指令集架构上运行的操作系统。 这个系列的大部分文章和知识来自于:[完结] 循序渐进,学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春,以及相关的github地址。 在这个过程中,这个系列相当于是我的学习笔记,做

    2024年04月09日
    浏览(52)
  • 华为欧拉操作系统结合内网穿透实现固定公网地址SSH远程连接

    欧拉操作系统(openEuler, 简称“欧拉”)是面向数字基础设施的操作系统,支持服务器、云计算、边缘openEuler是面向数字基础设施的操作系统,支持服务器、 云计算、边缘计算、嵌入式等应用场景,支持多样性计算,致力于提供安全、稳定、易用的操作系统 Cpolar是一种安全的内网

    2024年01月23日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包