c++/c混合编程

2023-11-16

一、前言

        代码从编写到能执行之前,需要经过编译、链接阶段。通常,编译每一个单元文件会生成目标文件,然后链接器会把各个目标文件链接起来生成可执行性文件。链接器之所以能把目标文件相互之间链接起来,就是通过查找目标文件中的唯一函数符号(即经过编译器去编译修饰后,重新得到的函数符号)。

        C和C++编译器对编译函数符号的生成规则是不一样的,例如对于函数void fun(int a, int b),C经过编译后生成的符号为_fun, C链接器链接的时候就会去找_fun这样的函数符号;在C++中,生成的类似为_fun_int_int, 新生成的符号名不仅带有函数名,还有参数类型。正因为他们两者编译函数的时候,生成的符号规则不一样,所以,在混合编程中,如果我们不进行任何处理,而相互效用的话,必然会出现在链接的时候,找不到符号链接的情况。

ps : c++符号名称的规则,并没有一种唯一的命名规范, 不同的编译器命名规范不同, 但是思路一致! 如下图所示 :

        为什么编译器在设计的时候要这么设计生成的符号呢?

        因为C只有单一的命名空间,不支持函数重载之类的特性

        C++为了支持函数重载(即函数名字可以相同,参数类型或个数不同),允许存在同名的函数;且C++甚至可以存在相同的类型、变量等,因为在C++中命名空间的存在。

二、extern "C"

extern "C"的真实目的是实现类C和C++的混合编程。

在C++调用C的时候, 告诉C++编译器, 编译的时候,不要用默认的C++规范查找, 而要采用C规范去查找。

在C调用C++的时候, 告诉C++编译器, 编译的时候, 不要按照C++默认的规范去编译, 而应该按照C规范去编译。

三、c++引用c

1、简单示例

// 注意: 该代码是C程序, 请放在.c文件中, 这样确保是C编译器
 
#include <stdio.h>
 
void fun()
{
	printf("ok\n");
}
// 注意: 该代码是C++程序, 请放在.cpp文件中, 这样确保是C++编译器
 
#include <iostream.h>
 
extern "C" void fun(); // 暂时骗过编译器, 并对链接器说, 你要按照C规范链接, 去找_fun, 而不是"?fun@@YAXXZ"
 
int main()
{
	fun();
 
	return 0;
}

2、代码优化:

既然#include相当于文本拷贝, 那为何不把extern "C" 语句放到头文件中呢?
但是我很遗憾的告诉大家, 如果你这样做的话, 那么C文件就不能调用C文件的方法了!因为C的编译器不支持 extern "C" 语法!这里要引出一个宏, __cplusplus, 只要是C++文件, 编译器就会自动定义一个这样的宏, 我们就能利用这个宏做到C/C++的终极混编了!

// --------------cfun.h
#ifndef __C_FUN_H__
#define __C_FUN_H__
 
#ifdef __cplusplus
extern "C"{
#endif // __cplusplus
 
	void cfun();
#ifdef __cplusplus
}
#endif
 
 
#endif
// --------------cfun.c
#include "cfun.h"
#include <stdio.h>
 
void cfun()
{
	printf("hello world.\n");
}
// --------------main.cpp
#include <iostream>
#include "cfun.h"

int main()
{
	cfun();
	system("pause");
	return 0;
}

四、c引用c++

核心就是告诉C++编译器, 编译的时候, 不要按照C++默认的规范去编译, 而应该按照C规范去编译。其次,要实际谨记,include就是原地展开,这样就容易理解了!

方式1、函数在cpp文件中定义的时候使用extern "C"修饰

// cal.cpp 

extern "C" int sum(int a, int b)
{
    return a + b;
}
// hyber_test.c 

#include <stdio.h>
extern int sum(int a, int b);

int main()
{
    printf("sum:%d\n", sum(1,2));
}

 

方式2、在cpp头文件声明的时候使用extern "C"修饰

在cpp文件中用下列方式定义函数:

returnType FunName(parameters list).

然后在相应的头文件中进行声明:

extern "C" returnType FunName(parameters list);

在相应的.c文件中添加函数声明(extern returnType FunName(parameters list);),然后直接利用相应的函数即可.

cal.h:

#ifndef CAL_HEADER
#define CAL_HEADER

extern "C" int sum(int a, int b);

#endif CAL_HEADER

cal.cpp:

// cal.cpp 

#include <cal.h>

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

在C的代码文件main.c中调用print函数:

// hyber_test.c 

#include <stdio.h>
extern int sum(int a, int b);
int main()
{
    printf("sum:%d\n", sum(1,2));
}

note:

在C的代码文件中直接#include "cal.h"头文件,编译出错。

而且如果不加extern int sum(int a, int b);编译也会出错。

ref:

再谈谈只针对C++编译器/链接器的extern “C“------C与C++的相互调用_涛歌依旧的博客-CSDN博客

遇到问题 --- C++调用C静态库,出现undefined reference的问题 - 蜗牛的博客 | VK's Blog

C++程序中出现undefined reference to ......_阿卡基YUAN的博客-CSDN博客_undefinedreferenceto是什么意思

C和C++混合编译,extern和extern "C" - 云+社区 - 腾讯云

C/C++混合编程_embed_huang的博客-CSDN博客_c c++混合编程

浅谈C/C+混合编程 - 知乎

c/c++实现混合编程 - heity - 博客园

【重新认识C++】08-extern C2-C、C++混合开发_哔哩哔哩_bilibili

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++/c混合编程 的相关文章

  • C++_生成随机字符串

    include
  • C#中unsafe的使用

    1 unsafe在C 程序中的使用场合 实时应用 采用指针来提高性能 引用非 net DLL提供的如C 编写的外部函数 需要指针来传递该函数 调试 用以检测程序在运行过程中的内存使用状况 2 使用unsafe的利弊 好处是 性能和灵活性提高
  • C++操作SQLite数据库

    准备工作 在使用C 操作SQLite之前 需要获得sqlite3 h sqlite3 lib sqlite3 dll 大家可以在 这里 下载 并将这3个文件导入VC 工程中 其中sqlite3 dll文件放到Debug文件夹里 SQLite
  • R语言学习笔记:分析学生的考试成绩

    孩子上初中时拿到过全年级一次考试所有科目的考试成绩表 正好可以用于R语言的统计分析学习 为了不泄漏孩子的姓名 就用学号代替了 感兴趣可以下载测试数据进行练习 num class chn math eng phy chem politics
  • IUnknown—COM和MFC

    转自 http hi baidu com zhangqiuxi blog item 6d9603ad9c8fe5084b36d6a0 html 问题 我用MFC编写COM程序有一段时间了 知道如何使用宏和嵌套类 以及如何在嵌套类中处理IUn
  • C++中的namespace

    namespace中文意思是命名空间或者叫名字空间 传统的C 只有一个全局的namespace 但是由于现在的程序的规模越来越大 程序的分工越来越细 全局作用域变得越来越拥挤 每个人都可能使用相同的名字来实现不同的库 于是程序员在合并程序的
  • std::nth_element bug引起的crash问题

    1 源码 auto less compare const MirroringGroup mg1 const MirroringGroup mg2 gt bool return mg1 usage lt mg2 usage std nth e
  • C/C++ 引用作为函数的返回值

    语法 类型 函数名 形参列表 函数体 特别注意 1 引用作为函数的返回值时 必须在定义函数时在函数名前将 2 用引用作函数的返回值的最大的好处是在内存中不产生返回值的副本 代码来源 RUNOOB include
  • 使用QZXing生成并解析二维码

    QZxing 是对 zxing 的一个封装 用于在 Qt 程序中加入条形码和二维码识别的功能 这里就讲讲如何编译和使用这个库 前几年 QZXing 的代码是放到 sourceforge net 上的 现在迁移到了 github com 所以
  • 如何学好C语言的数据结构与算法?

    C语言的数据结构与算法 难就难在链表 学会了链表 可能后面就一点都不难了 书籍推荐 数据结构与算法分析 C语言描述版 要深入学习的话可以选择这本书 因为针对链表的讲解是比较详细的 所以可以很快理解链表 跟着书上一点点实现基本操作 增删改查
  • BP学习算法-构建三层神经网络

    引 人工神经网络 Artificial Neural Networks 简写为ANNs 也简称为神经网络 NNs 或称作连接模型 Connection Model 是一种模仿动物神经网络行为特征 进行分布式并行信息处理的算法数学模型 这种网
  • vector,list,deque区别

    http blog csdn net renkaihao article details 6803866 vector和built in数组类似 它拥有一段连续的内存空间 并且起始地址不变 因此它能非常好的支持随即存取 即 操作符 但由于它
  • lua和测试(一)

    lua做为一门高级语言 在游戏产业运用到机会越来越多了 测试掌握几门脚本语言也有一定的重要性 以下对于lua组合输入做出一些引导 测试需要掌握的关于返回数值 主要用到布尔类 前言的指引 lua的语法比较简单和清晰 学过c语言的可以很好的掌握
  • Trace Function Enter, Exit and Leave

    http developer nokia com community wiki Trace Function Enter Exit and Leave
  • Public Private Protect Inheritance and access specifiers

    In the previous lessons on inheritance we ve been making all of our data members public in order to simplify the example
  • 一个简单的参数帮助框架,c实现

    文章目录 具体实现如下 include
  • 虚函数不能声明为static

    虚函数申明为static报错 class Foo public Foo default static virtual Foo int main Foo foo return 0 main cpp 10 25 error member Foo
  • C/C++编程:令人印象深刻的高级技巧案例

    C C 编程语言在软件开发领域有着悠久的历史 由于其高效 灵活和底层访问能力 至今仍然被广泛应用 本文将介绍一些在C C 编程中令人印象深刻的高级技巧 帮助读者提升编程水平 更加高效地使用这两种强大的编程语言 一 指针运算与内存管理 C C
  • C++ 字符串比较------strcmp函数和strncmp函数

    strcmp 函数原型 int strcmp const char str1 const char str2 功能 strcmp函数会按照字典顺序逐个比较两个字符串的字符 直到遇到不同的字符或者遇到字符串结束符 0 返回值 该函数返回值如下
  • C 语言运算符详解

    C 语言中的运算符 运算符用于对变量和值进行操作 在下面的示例中 我们使用 运算符将两个值相加 int myNum 100 50 虽然 运算符通常用于将两个值相加 就像上面的示例一样 它还可以用于将变量和值相加 或者将变量和另一个变量相加

随机推荐

  • 计算器ajax实现代码,用JQuery写一个计算器

    因为觉得segment fault的markdown界面比CSDN漂亮一些 所以最近正在把博客迁移到这边来 这几天多发了两篇 作为一个学习中练手的小demo 选了一个计算器 原因大概只是因为早就想做 比较简单 又确实有很多地方不太清楚 所以
  • PAT 1011 A+B 和 C

    给定区间 2 31 2 31 内的 3 个整数 A B 和 C 请判断 A B 是否大于 C 注意本题数字的范围 是 2 31 2 31 因此要用long long 类型 刚开始用了int 类型 一直提示有错误 注意int 32位 可以包括
  • 开发规范-java代码注释及IDEA配置代码注释模板

    引 阿里巴巴开发规范 注释规约 强制 类 类属性 类方法的注释必须使用 Javadoc 规范 使用 内容 格式 不得使用 xxx 方式 说明 在 IDE 编辑窗口中 Javadoc 方式会提示相关注释 生成 Javadoc 可以正确输出相应
  • python正则表达式从字符串中提取数字的思路详解(转载)

    python从字符串中提取数字 使用正则表达式 用法如下 总结 匹配字符串的开始 匹配字符串的结尾 b 匹配一个单词的边界 d 匹配任意数字 D 匹配任意非数字字符 x 匹配一个可选的 x 字符 换言之 它匹配 1 次或者 0 次 x 字符
  • Unity - 无限循环列表

    效果和UI结构 效果 Tips 免费的视频转GIF网站 UI结构 父节点为一个Panel Panel的Vertical Layout Group方便快捷调整Panel下的Image子物体的位置 使用时取消组件 Image是列表的子物体 只有
  • CSS文字自动换行

    word break属性 normal 只在允许的断字点换行 浏览器保持默认处理 break word 在长单词或 URL 地址内部进行换行 white space属性 normal 默认 空白会被浏览器忽略 pre 空白会被浏览器保留 其
  • Java编程那些事儿88——文件操作之写文件

    Java编程那些事儿88 文件操作之写文件 陈跃峰 出自 http blog csdn net mailbomb 11 3 1 4 写文件 如前所述 将程序内部的数据输出到程序外部的数据源 应该使用IO类体系中的输出流 在实际的编程中 将程
  • MATLAB设计滤波器之新版filterDesigner使用

    一 引言 本篇内容主要介绍新版Matlab的滤波器设计filterDesigner工具的使用 并以设计两个带通滤波器为使用的例子 使用的MATLAB软件版本为MATLAB R2022a 二 filterDesigner设计滤波器 1 在命令
  • C++责任链模式:Chain of Responsibility Pattern

    当你想要让一个以上的对象有机会能够处理某个请求的时候 就可以使用责任链模式 责任链模式 将请求的发送和接收解耦 让多个接收对象都有机会处理这个请求 将这些接收对象串成一条链 并沿着这条链传递这个请求 直到链上的某个接收对象能够处理它为止 通
  • Ubuntu18.04装Miniconda后终端出现base环境

    在 Ubuntu18 04LTS DELL 台式机中安装 Pytorch 由于没有 GPU 只能下载仅使用 CPU 版的 Pytorch 去 Pytorch 官网按照文档 Start Locally PyTorch 一步步下载相应的环境 P
  • tomcat8下启动 jsp报错

    The method getDispatcherType is undefined for the type HttpServletRequest java lang ClassNotFoundException org apache js
  • PLSQL中的FOR循环

    游标的FOR循环 循环体是查询的表 游标的for循环 PL SQL 语言提供了 游标 FOR 循环语句 自动执行游标的 OPEN FETCH CLOSE 语句和 循环 语句的功能 当进入循环时 游标 FOR 循环语句 自动 打开游标 并提取
  • LCD调试流程

    本来想学的更深入一些再来写这些总结 但想想 边学边写 记录成长过程也挺好的 下面自底向上 了解LCD的整个工作流程 一 LCD的组成结构和各结构的功能 1 背光板模组 提供光的来源 2 上下偏光板 TFT Glass Substrate 液
  • 【C/C++学习笔记】c++ 回调函数

    1 介绍 回调函数就是一个通过函数指针调用的函数 如果你把函数的指针 地址 作为参数传递给另一个函数 当这个指针被用来调用其所指向的函数时 我们就说这是回调函数 回调函数不是由该函数的实现方直接调用 而是在特定的事件或条件发生时由另外的一方
  • Maven自动化构建工具详解

    一 Maven概述 1 使用Maven原因 我们先通过企业开发中的实际需求来看一看哪些方面是我们现有技术的不足 1 第三方Jar包添加 在今天的JavaEE开发领域 有大量的第三方框架和工具可以供我们使用 要使用这些jar包最简单的方法就是
  • win7+ubuntu20.04双系统安装,以及pointnet2_pytorch编译记录

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 win7 ubuntu20 04双系统安装 二 Ubuntu安装相关 1 Anaconda 2 Nvidia Driver 3 编译pointnet2 p
  • SSM框架-SpringMVC详解

    springmvc概述 Springmvc是spring框架的一个模块 spring和springmvc无需中间整合层整合 Springmvc是一个基于mvc的web框架 表现层的三大任务 URL到controller的映射 http请求参
  • 【MySQL】20个经典面试题,全部答对月薪10k+

    欢迎加入QQ群讨论更多内容 群号 835870546 原文链接 http bbs 51cto com thread 1470880 1 html Part2 经典题目 1 MySQL的复制原理以及流程 基本原理流程 3个线程以及之间的关联
  • IntelliJ Idea 常用快捷键列表

    IntelliJ Idea 常用快捷键列表 Alt 回车 导入包 自动修正 Ctrl N 查找类 Ctrl Shift N 查找文件 Ctrl Alt L 格式化代码 Ctrl Alt O 优化导入的类和包 Alt Insert 生成代码
  • c++/c混合编程

    一 前言 代码从编写到能执行之前 需要经过编译 链接阶段 通常 编译每一个单元文件会生成目标文件 然后链接器会把各个目标文件链接起来生成可执行性文件 链接器之所以能把目标文件相互之间链接起来 就是通过查找目标文件中的唯一函数符号 即经过编译