【C与C++的相互调用方法】

C与C++的相互调用方法

  • C与C++为什么相互调用的方式不同
  • C++中调用C
  • C中调用C++
  • 致谢

C与C++为什么相互调用的方式不同

  C 和 C++ 之间的相互调用方式存在区别,主要是由于 C 和 C++ 语言本身的设计和特性不同。

  • 函数调用和参数传递方式不同:C 和 C++ 在函数调用和参数传递方面有一些不同之处。C 使用标准的函数调用约定,而 C++ 在函数调用中可能包含额外的信息,如函数重载和默认参数。为了正确匹配函数签名,C++ 编译器可能会在函数名上进行名称修饰(name mangling)。
  • 函数重载和名称修饰:C++ 支持函数重载,即可以有相同的函数名但不同的参数列表。为了在可执行文件中区分这些重载函数,C++ 编译器会在函数名中添加一些信息,以便于重载解析。这与 C 的函数名约定不同,C 中函数名是平铺的。
  • 链接库的差异:C 和 C++ 编译器链接不同的标准库。C 编译器链接 C 标准库,而 C++ 编译器链接 C++ 标准库。由于标准库可能涉及不同的函数和数据结构,因此在链接阶段可能会有不同的处理。
  • 编译器特性:C 和 C++ 编译器对代码的解析、优化、链接等可能会有不同的处理方式,这可能会导致在 C 和 C++ 相互调用时需要进行适当的处理。

  解决手段:为了在 C 和 C++ 之间实现相互调用,C++ 引入了 extern “C” 语法,它可以用来告诉 C++ 编译器在函数声明上使用 C 的调用约定,以便在链接阶段能够正确解析函数名。这种设计是为了在 C 和 C++ 之间实现互操作性,但由于两者的语法和特性存在差异,因此在调用方式、编译器行为和链接方式上会存在一些差异。

C++中调用C

  话不多说,直接上案例,下面是一个简单的示例,演示了如何在 C++ 代码中调用 C 函数:

首先分别创建三个文件:mylib.cmylib.hmain.cpp

  mylib.c如下:

// mylib.c
#include <stdio.h>

void my_c_function() {
    printf("This is a C function.\n");
}

  mylib.h如下:

// mylib.h
#ifndef MYLIB_H
#define MYLIB_H

void my_c_function();

#endif // MYLIB_H

  main.cpp如下:

// main.cpp
#include <iostream>

extern "C" {
    // 声明 C 函数的原型
    void my_c_function();
}

int main() {
    std::cout << "Calling a C function from C++:" << std::endl;

    // 调用 C 函数
    my_c_function();

    return 0;
}

  在这个示例中,我们使用了 #include "mylib.h" 来引入头文件,并在 C++ 中调用了 my_c_function()。这样就能正确地在 C++ 中调用 C 函数。编译步骤如下:

gcc -c mylib.c -o mylib.o   # 编译 C 文件为目标文件
g++ -c main.cpp -o main.o   # 编译 C++ 文件为目标文件
g++ main.o mylib.o -o app  # 链接目标文件生成可执行文件

  编译后的文件列表如下:
在这里插入图片描述
  然后运行可执行文件:./app得到输出结果:
在这里插入图片描述
  这里可以使用objdump命令查看编译之后的中间文件mylib.omain.o的符号表:
在这里插入图片描述
在这里插入图片描述
  可以发现,my_c_function()函数编译出的名称在mylib.omain.o是相同。这是由于 C++ 文件中使用 extern “C” 来声明 C 调用约定,以便 C 能够正确解析函数名。
  我们来看看如果没有使用extern “C” 后的编译情况吧:
在这里插入图片描述
  可以发现,不使用 extern “C”, 函数 my_c_function 编译后名称变为了 (_Z13my_c_functionv)
  是由于在C++中,函数名在编译后会根据函数的参数类型和返回类型进行名称重整(Name Mangling),以支持函数重载等特性。这是因为C++支持函数的参数类型和个数可以不同,所以需要在编译后为每个函数生成一个唯一的名称。
  当你在C++中调用一个C函数时,如果不使用 extern “C” 声明,C++ 编译器会默认对函数名进行名称重整。而在C语言中,函数名不会被重整。
  如果你在C++中调用了一个C函数,并且没有使用 extern “C” 声明,C++ 编译器会对函数名进行名称重整,生成一个新的名字,类似 _Z13my_c_functionv 这样的名称。这个过程被称为名称重整(Name Mangling),是为了确保函数在C++中能够正确处理函数重载等特性。

C中调用C++

  下面还是来看一个简单的示例,演示了如何在 C 代码中调用 C++ 函数:

首先分别创建三个文件:mylib.cppmylib.hmain.c

  mylib.cpp如下:

// mylib.cpp
#include <iostream>

#include "mylib.h"

void my_cpp_function(int num) {
    std::cout << "C++ function called with number: " << num << std::endl;
}

  mylib.h如下:

// mylib.h
#ifndef MYLIB_H
#define MYLIB_H

#ifdef __cplusplus
extern "C" {
#endif

    void my_cpp_function(int num);

#ifdef __cplusplus
}
#endif

#endif // MYLIB_H

#endif // MYLIB_H

  main.c如下:

// c_main.c
#include <stdio.h>

#include "mylib.h"

int main() {
    printf("Calling C++ function from C\n");
    
    // Call the C++ function
    my_cpp_function(42);
    
    return 0;
}

  在这个示例中,我们使用了 #include "mylib.h" 来引入头文件,并在 main.c 中调用了 my_cpp_function()。这样就能正确地在 C 中调用 C++ 函数。编译步骤如下:

g++ -c mylib.cpp -o mylib.o   # 编译 C 文件为目标文件
gcc -o main main.c mylib.o -lstdc++  # 链接目标文件生成可执行文件

注释-lstdc++ 是用于链接 C++ 标准库的编译选项。在Linux系统中,C++ 标准库通常被命名为 libstdc++.so,使用 -lstdc++ 编译选项可以将这个库链接到可执行文件中,以便在运行时使用C++的标准库函数和功能。

  如果缺少 -lstdc++ 则会报错:
在这里插入图片描述
  编译后的文件列表如下:
在这里插入图片描述
  然后运行可执行文件:./main得到输出结果:
在这里插入图片描述
  这里解释一下mylib.h头文件中的 #ifdef __cplusplus:在main.c文件夹中调用mylib.h头文件,但是 C 语言中并没有 extern 这个关键字,因此,使用 #ifdef __cplusplus来充当一个译时候的阀门。
  总结一下:对于C调用C++的情况,没有 extern “C” 这样的关键字。您需要在C++代码中使用 extern “C” 来确保C++函数按照C的方式进行链接,同时在C代码中包含相应的头文件并调用这些函数。

致谢

  本文的学习参考了以下文章:C与C++如何互相调用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/72948.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker — 容器网络

一、概述 Docker容器每次重启后容器ip是会发生变化的。 这也意味着如果容器间使用ip地址来进行通信的话&#xff0c;一旦有容器重启&#xff0c;重启的容器将不再能被访问到。 而Docker 网络就能够解决这个问题。 Docker 网络主要有以下两个作用&#xff1a; 容器间的互联…

docker部署springboot

基础知识 什么是docker 官网&#xff1a; Docker Docs: How to build, share, and run applications | Docker Documentation Docker 是一个基于go语言开发的开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到…

97. Interleaving String 72. Edit Distance 121. 122. 123

​​​​​​97. Interleaving String 72. Edit Distance 一个bottomup&#xff08;棋盘从右下角外围逼近[0,0]&#xff09;如果横轴是string1的index i&#xff0c;纵轴string2的index j&#xff0c;那么&#xff0c;很奇妙的是i和j一起&#xff08;从右下角的格子看&#xf…

11.Eclipse 注释模板的说明及设置

1.在eclipse中点击Window——>java——>Code Style——>CodeTemplates——>Comments 2.常用Variable 3. 我的注释模板 ①Files 文件 /** * Title: ${file_name}* Description: ${todo}* author Jeremy* date ${currentDate:date(yyyy-MM-dd hh:mm:ss)} */ ②Typ…

Kotlin入门:变量和函数——02

目录 一、Kotlin 基本数据类型 ​编辑 二、变量 val 关键字&#xff1a; var 关键字: 类型推断: 可空类型: 三、函数 基本函数语法&#xff1a; 单表达式函数&#xff1a; 默认参数值&#xff1a; 命名参数&#xff1a; 一、Kotlin 基本数据类型 Kotlin 的基本数…

树结构--介绍--二叉树遍历的递归实现

目录 树 树的学术名词 树的种类 二叉树的遍历 算法实现 遍历命名 二叉树的中序遍历 二叉树的后序遍历 二叉树的后序遍历迭代算法 二叉树的前序遍历 二叉树的前序遍历迭代算法 树 树是一种非线性的数据结构&#xff0c;它是由n(n≥0)个有限节点组成一个具有层次关系…

中电金信:ChatGPT一夜爆火,知识图谱何以应战?

随着ChatGPT的爆火出圈 人工智能再次迎来发展小高潮 那么作为此前搜索领域的主流技术 知识图谱前路又将如何呢&#xff1f; 事实上&#xff0c;ChatGPT也并非“万能”&#xff0c;作为黑箱模型&#xff0c;ChatGPT很难验证生成的知识是否准确。并且ChatGPT是通过概率模型执行推…

Django入门

Day1 django环境安装 创建虚拟环境 # step1 创建虚拟环境 python3 -m venv datawhale_django # step2 mac进入虚拟环境 source ./datawhale_django/bin/activate # step3 退出虚拟环境 deactivate安装包 pip3 install django ​pip3 install djangorestframework​​ pip3 …

Jenkins自动化打包脚本

一、背景 jenkins可以设置定时任务打包&#xff0c;也已手动点按钮打包&#xff0c;还可以通过执行http请求打包&#xff0c;今天我们就通过shell脚本&#xff0c;通过curl命令进行jenkins打包。 二、步骤 2.1 在jenkins上构建项目 设置触发器 2.2 通过shell脚本触发远程构…

电商财务新时代:轻松自动对账,财务效率倍增

电商领域频繁的多平台财务对账常常令企业头痛不已。然而&#xff0c;随着轻易云数据集成平台的崭新解决方案&#xff0c;财务对账的痛点迎刃而解。本文通过引人入胜的实例&#xff0c;深入探讨电商财务对账的现状&#xff0c;突出轻易云数据集成平台在自动对账中的强大作用&…

感受RFID服装门店系统的魅力

嘿&#xff0c;亲爱的时尚追随者们&#xff01;今天小编要给你们带来一股时尚新风潮&#xff0c;让你们感受一下什么叫做“RFID服装门店系统”&#xff0c;这个超酷的东西&#xff01; 别着急&#xff0c;先别翻白眼&#xff0c;小编来解释一下RFID是什么玩意儿。它是射频识别…

RFID技术助力半导体制造行业自动化生产

由于芯片短缺问题和近2年海运拥堵和成本上升等因素&#xff0c;致使全球资本对于芯片制造工厂的投入增大&#xff0c;而中兴、华为的例子已经凸显出国产半导体供应链的重要性&#xff0c;除去地缘政治上的意义&#xff0c;发展半导体其实是中国经济的转型的必走之路。 半导体生…

Programming abstractions in C阅读笔记:p107-p110

《Programming Abstractions In C》学习第46天&#xff0c;p107-p110&#xff0c;3.1小节——“The concept of interface”&#xff0c;总结如下&#xff1a; 一、技术总结 1.client p108&#xff0c;调用library的program称为client。 2.interface p108&#xff0c;“To do …

【刷题笔记8.13】【动态规划相关】LeetCode题目:斐波那契数列、爬楼梯

【动态规划相关】LeetCode题目&#xff1a;斐波那契数列、爬楼梯 &#xff08;一&#xff09;爬楼梯 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 提示&#xff1a; 1 < n <…

第57步 深度学习图像识别:CNN可视化(Pytorch)

基于WIN10的64位系统演示 一、写在前面 由于不少模型使用的是Pytorch&#xff0c;因此这一期补上基于Pytorch实现CNN可视化的教程和代码&#xff0c;以SqueezeNet模型为例。 二、CNN可视化实战 继续使用胸片的数据集&#xff1a;肺结核病人和健康人的胸片的识别。其中&…

CSS变形与动画(一):transform变形 与 transition过渡动画 详解(用法 + 代码 + 例子 + 效果)

文章目录 变形与动画transform 变形translate 位移scale 缩放rotate 旋转skew 倾斜多种变形设置变形中心点 transition 过渡动画多种属性变化 变形与动画 transform 变形 包括&#xff1a;位移、旋转、缩放、倾斜。 下面的方法都是transform里的&#xff0c;记得加上。 展示效…

pconsc4 安装

Pconsc4 安装遇到的问题 Pconsc4-github 按照红框给的一行命令&#xff0c;一行毁所有。 1 gcc and g not found # 1 Start by updating the packages list:sudo apt update# 2 Install the build-essential package by typing:sudo apt install build-essential## The comm…

在 Windows 中恢复数据的 5 种方法

发生数据丢失的原因有多种。无论是因为文件被意外删除、文件系统或操作系统损坏&#xff0c;还是由于软件或硬件级别的存储故障&#xff0c;数据都会在您最意想不到的时候丢失。今天我们重点介绍五种数据恢复方法&#xff0c;以应对意外情况的发生。 1.从另一台机器启动硬盘 如…

MyBatis-Plus学习笔记(尚硅谷)

一、MyBatis-Plus 1.简介 MyBatis-Plus (opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 我们的愿景是成为 MyBatis 最好的搭档&…