C 与 C++ 接口函数相互调用的实现

一、C 或 C++ 编译的四个步骤

(一) 预处理

在该步骤中,编译器将源程序中以“#”开头的语句进行处理。其中,#include 的原理是将目标文件内容导入本文件。

(二) 编译

在该步骤中,编译器将第一步生成的各个文件分别转换成汇编语言文件。在该过程中,所有函数的名称都会被转换成一个符号作为汇编文件中的唯一标识,对 C 语言函数一般直接用函数名称作为其唯一标识的符号,而对于 C++ 函数在多数情况下需要在函数名称加上各种前缀或后缀才能作为其标识,比如函数 void Print(int num),如果编译器将其视为 C 语言编译,则该函数在汇编文件中的符号为 Print,若视为 C++,则其符号可能为 Print_int(在 gcc 或 g++ 中函数名称的改变还会考虑命名空间等因素),这也是 C++ 支持函数重载的原因。

(三) 汇编

在该步骤中,编译器将第二步生成的各个文件分别转换为二进制文件,但还不是可执行文件。

(四) 链接

在该步骤中,编译器会为第三步生成的每一个文件“穿针引线”,比如 main() 函数中调用了 Print() 函数,还不知道 Print() 函数在哪里,而在 Print() 函数主体所在的那个文件中,已经标明了 Print() 函数的地址,所以编译器会在 main() 函数中调用 Print() 函数的地方标注 Print() 函数的地址,为程序执行过程中的地址跳转提供目标地址,而编译器能做到这一步的前提,是 main() 函数中 Print() 函数的标识,和 Print() 函数主体所在的那个文件中 Print() 函数的标识是一模一样的,如果不一样,就会触发链接错误。

二、C 与 C++ 接口相互调用的关键

从上文可以得知,要调用一个函数有一个重要条件就是调用处的符号和函数主体处的符号要一模一样,而 C 和 C++ 在编译过程中将函数名称改编成标识符号的方法是不一样的,因此相互调用的关键在于统一接口函数的标识符号,而一般采取的方法是,用 C 函数改编的方法统一接口函数的改编方式。

三、extern "C"

extern "C" 的作用是告诉编译器按 C 函数名称改编的方法将修饰的函数改编成标识符号。extern "C" 一般用在 C++ 文件中。

extern "C" void Print(int num);
extern "C" {
 void Input(int* num);
 void Output(int num);
};

以上是 extern "C" 的两种写法。如此一来,以上三个函数都会按 C 的方式被改编成符号,在 gcc 或 g++ 编译下就会被改变成 Print,Input,Output。

四、C 函数调用 C++ 接口

(一) 调用非成员函数

被调用函数的声明和定义如下。

/**
 * called.h
 */
#ifndef CALLED_H
#define CALLED_H

extern "C" void PrintCpp(void);

#endif
/**
 * called.cpp
 */
#include <iostream>
#include "called.h"

using namespace std;

void
PrintCpp(void) {
 cout << "I\'m cpp." << endl;
}

最终调用如下。

/**
 * call.c
 */
#include "called.h"

int
main(int argc, char const* argv[]) {
 PrintCpp();
 return 0;
}

(二) 调用类成员函数(接口函数没有类指针)

被调用函数声明和定义如下。

/**
 * called.h
 */
#ifndef CALLED_H
#define CALLED_H

class Console {
public:
 Console();
 virtual void PrintDouble(double num);
};

extern "C" void CppPrintDouble(double num);

#endif
/**
 * called.cpp
 */
#include <iostream>
#include "called.h"

using namespace std;

Console::Console() {}

void
Console::PrintDouble(double num) {
 cout << num << endl;
}

Console* console = new Console();

void
CppPrintDouble(double num) {
 console->PrintDouble(num);
}

最终调用如下。

/**
 * call.c
 */
#include "called.h"

int
main(int argc, char const* argv[]) {
 CppPrintDouble(3.14);
 return 0;
}

五、C++ 函数调用 C 接口

被调用函数的声明和定义如下。

/**
 * called.h
 */
#ifndef CALLED_H
#define CALLED_H

void PrintC(void);

#endif
/**
 * called.c
 */
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif
#include "called.h"
#ifdef __cplusplus
};
#endif

void
PrintC(void) {
 printf("I\'m C.\n");
}

最终调用如下。

/**
 * call.cpp
 */
#ifdef __cplusplus
extern "C" {
#endif
#include "called.h"
#ifdef __cplusplus
};
#endif

int
main(int argc, char const* argv[]) {
 PrintC();
 return 0;
}

在 called.c 文件中,#ifdef __cplusplus /*...*/ #endif 和 extern "C" 的作用是防止 g++ 编译器对“.c”文件用 C++ 的方式编译,如果用 gcc 进行编译,则直接写 #include "called.h" 就行。

到此这篇关于C 与 C++ 接口函数相互调用的实现的文章就介绍到这了,更多相关C 与 C++ 接口函数调用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++调用迅雷接口解析XML下载功能(迅雷下载功能)

    迅雷下载库的网址:http://thunderplatform.xunlei.com 复制代码 代码如下: // FileName: Download.h#pragma once#include "lib\XLDownload.h"#include "lib\XLError.h"#include <vector> // 下载队列的大小,决定同时开启下载线程的数量const int LIMIT = 2; struct Down{    // 解析出来的下载

  • Python调用C++,通过Pybind11制作Python接口

    我是在ubuntu系统进行实验的,所以和window可能会有区别. python调用C/C++有不少的方法,如boost.python, swig, ctypes, pybind11等,这些方法有繁有简,而pybind11的优点是对C++ 11支持很好,API比较简单,现在我们就简单记下Pybind11的入门操作. 1. pybind11简介与环境安装 pybind11是一个轻量级的只包含头文件的库,它主要是用来在已有的 C++代码的基础上做扩展,它的语法和目标非常像Boost.Python,但

  • C 与 C++ 接口函数相互调用的实现

    一.C 或 C++ 编译的四个步骤 (一) 预处理 在该步骤中,编译器将源程序中以"#"开头的语句进行处理.其中,#include 的原理是将目标文件内容导入本文件. (二) 编译 在该步骤中,编译器将第一步生成的各个文件分别转换成汇编语言文件.在该过程中,所有函数的名称都会被转换成一个符号作为汇编文件中的唯一标识,对 C 语言函数一般直接用函数名称作为其唯一标识的符号,而对于 C++ 函数在多数情况下需要在函数名称加上各种前缀或后缀才能作为其标识,比如函数 void Print(in

  • .net中前台javascript与后台c#函数相互调用问题

    C#代码与javaScript函数的相互调用 问: 1.如何在JavaScript访问C#函数? 2.如何在JavaScript访问C#变量? 3.如何在C#中访问JavaScript的已有变量? 4.如何在C#中访问JavaScript函数? 问题1答案如下: javaScript函数中执行C#代码中的函数: 方法一:1.首先建立一个按钮,在后台将调用或处理的内容写入button_click中;         2.在前台写一个js函数,内容为document.getElementById("

  • c#和javascript函数相互调用示例分享

    在设置过webBrowser控件的ObjectForScripting属性后,还需要设置应用程序对com可见,不然会抛出一个异常(ObjectForScripting 的类必须对 COM 可见.请确认该对象是公共的,或考虑向您的类添加 ComVisible 属性.),可做如下设置: [System.Runtime.InteropServices.ComVisible(true)] 例如: 复制代码 代码如下: [ComVisible(true)]    public partial class

  • C语言与Lua之间的相互调用详解

    前言 第一次接触Lua是因为Unity游戏中需要热更,但是一直没搞懂Lua是怎么嵌入到别的语言中执行的,如何互相调用的. lua是扩展性非常良好的语言,虽然核心非常精简,但是用户可以依靠lua库来实现大部分工作.除此之外,lua还可以通过与C函数相互调用来扩展程序功能.在C中嵌入lua脚本既可以让用户在不重新编译代码的情况下修改lua代码更新程序,也可以给用户提供一个自由定制的接口,这种方法遵循了机制与策略分离的原则.在lua中调用C函数可以提高程序的运行效率.lua与C的相互调用在工程中相当实

  • C#调用C++动态库接口函数和回调函数方法

    目录 1. 前言 2. 普通接口函数调用示例 2.1 C++端编写接口 2.2 C#端调用 3. 回调函数调用示例 3.1 C++端编写接口 3.2 C#端调用 1. 前言 需求: 当前C已经写好了一个动态库,完成了产品开发需求,C#需要调用C编写的动态库DLL接口,开发出完整的软件,DLL动态库里包含了普通接口函数,回调函数. 开发环境: win10 64位 .VS2017 2. 普通接口函数调用示例 2.1 C++端编写接口 (1)头文件里声明需要提供的接口,导出接口,方便C#调用 //带返

  • React Hook 父子组件相互调用函数方式

    目录 React Hook 父子组件相互调用函数 1.子组件调用父组件函数方法 2.父组件调用子组件函数方法 React Hook 父子组件传值 父组件 子组件 React Hook 父子组件相互调用函数 1.子组件调用父组件函数方法 //父组件 let Father=()=>{     let getInfo=()=>{              }     return ()=>{         <div>             <Children       

  • C#和lua相互调用的方法教程

    前言 自从ulua在官网上出来后,lua 就被u3d开发人员喜爱.国内有几个高手把lua拿过来 接着进行了封装.很多都是新手转过来.lua语法一看遍知,但是大多数人还是不明白两个语言之间的互相调用是怎么一回事,这也是难点和重点.所以今天想跟大家分享一下这方面的知识,让大家少走弯路吧. Lua是一种很好的扩展性语言,Lua解释器被设计成一个很容易嵌入到宿主程序的库.LuaInterface则用于实现Lua和CLR的混合编程. C与lua交互面临以下几个问题: 1.由于lua里面的数据都是动态加载的

  • Python与C/C++的相互调用案例

    一.问题 Python模块和C/C++的动态库间相互调用在实际的应用中会有所涉及,在此作一总结. 二.Python调用C/C++ 1.Python调用C动态链接库 Python调用C库比较简单,不经过任何封装打包成so,再使用python的ctypes调用即可. (1)C语言文件:pycall.c /***gcc -o libpycall.so -shared -fPIC pycall.c*/ #include <stdio.h> #include <stdlib.h> int f

  • python模块与C和C++动态库相互调用实现过程示例

    目录 Python调用C/C++ 1.Python调用C动态链接库 C语言文件:pycall.c gcc编译生成动态库libpycall.so Python调用动态库的文件:pycall.py 运行结果: 2.Python调用C/C++原生态导出 3.Python调用C/C++通过boost实现 4.Python调用C/C++通过导出类 5.Python调用C/C++通过导出变参函数 6.Python调用C/C++通过导出带Python对象的接口 Python调用C/C++ 1.Python调用

  • python 与c++相互调用实现

    目录 一.c++调用Python 1.Python脚本 2.C++调用python脚本 二.接口方法 1.规范化语法 三.Pthon调用c++ 1.基于extern 2.基于swig 一.c++调用Python 将Python安装目录下的include和libs文件夹引入到项目中,将libs目录下的python37.lib复制一份为python37_d.lib 1.Python脚本 def Hello():     print("Hello")       def Add(a,b):

随机推荐