C 和 C++ 动态库的跨语言调用原理

C 和 C++ 动态库封装及跨语言调用

在实际开发中,我们常常会将一部分功能封装成动态库(例如 .dll.so 文件),然后通过链接这些库来使用其中的函数。本文将展示如何封装 C 和 C++ 函数为动态库,并在 C 和 C++ 中进行跨语言调用。

1. 封装 C 函数为动态库

步骤:
  1. 编写 C 代码:定义 C 函数。
  2. 编译 C 代码为动态库:将 C 代码编译为共享库(.so 或 .dll)。
  3. 在 C++ 中调用 C 函数:通过动态链接调用 C 库中的函数。
示例代码:
  1. C 代码(c_func.c)
c 复制代码
// c_func.c
#include <stdio.h>

// C 函数:打印简单的问候语
void print_hello() {
    printf("Hello from C function!\n");
}
  1. 编译 C 代码为动态库

在 Linux 环境下,使用 gcc 编译 C 代码为动态库:

bash 复制代码
gcc -shared -o libcfunc.so -fPIC c_func.c

这将生成 libcfunc.so 动态库。对于 Windows 系统,命令可能是:

bash 复制代码
gcc -shared -o cfunc.dll -fPIC c_func.c
  1. C++ 代码(cpp_main.cpp)
cpp 复制代码
// cpp_main.cpp
#include <iostream>

// 声明 C 函数
extern "C" {
    void print_hello();  // 声明 C 函数
}

int main() {
    // 使用动态库中的 C 函数
    print_hello();  // 调用 C 函数
    return 0;
}
  1. 编译 C++ 代码并链接动态库

在 Linux 环境下,使用 g++ 编译并链接 C++ 代码与 C 动态库:

bash 复制代码
g++ -o cpp_main cpp_main.cpp -L. -lcfunc

-L. 指定动态库的目录,-lcfunc 表示链接名为 libcfunc.so 的动态库。

在 Windows 环境下,可以使用类似的命令:

bash 复制代码
g++ -o cpp_main cpp_main.cpp -L. -l cfunc
运行结果:
bash 复制代码
Hello from C function!
解释:
  • 我们编写了一个简单的 C 函数 print_hello,然后将其封装为动态库 libcfunc.so(在 Windows 上为 cfunc.dll)。
  • C++ 代码通过 extern "C" 声明该函数,并通过动态链接库调用它。执行 C++ 程序时,它会动态加载并执行 C 函数。

2. 封装 C++ 函数为动态库

步骤:
  1. 编写 C++ 代码:定义一个简单的类和一个成员函数。
  2. 编译 C++ 代码为动态库:将 C++ 代码编译为共享库(.so 或 .dll)。
  3. 在 C 中调用 C++ 函数:通过 C 风格的接口调用 C++ 动态库中的函数。
示例代码:
  1. C++ 代码(cpp_func.cpp)
cpp 复制代码
// cpp_func.cpp
#include <iostream>

class MyClass {
public:
    void print_message() {
        std::cout << "Hello from C++ function!" << std::endl;
    }
};

// 提供 C 风格接口供 C 调用
extern "C" void call_cpp_function() {
    MyClass obj;          // 创建 C++ 类的对象
    obj.print_message();  // 调用成员函数
}
  1. 编译 C++ 代码为动态库

在 Linux 环境下,使用 g++ 编译 C++ 代码为动态库:

bash 复制代码
g++ -shared -o libcppfunc.so -fPIC cpp_func.cpp

对于 Windows 系统,命令是:

bash 复制代码
g++ -shared -o cppfunc.dll -fPIC cpp_func.cpp
  1. C 代码(c_main.c)
c 复制代码
// c_main.c
#include <stdio.h>

// 声明 C++ 函数
extern void call_cpp_function();

int main() {
    // 调用 C++ 函数
    call_cpp_function();  // 通过 C 风格接口调用 C++ 函数
    return 0;
}
  1. 编译 C 代码并链接动态库

在 Linux 环境下,使用 gcc 编译 C 代码并链接 C++ 动态库:

bash 复制代码
gcc -o c_main c_main.c -L. -lcppfunc

在 Windows 上,类似的命令为:

bash 复制代码
gcc -o c_main c_main.c -L. -l cppfunc
运行结果:
bash 复制代码
Hello from C++ function!
解释:
  • C++ 动态库 libcppfunc.so(或在 Windows 上为 cppfunc.dll)中包含了一个类 MyClass 和一个成员函数 print_message,并通过 extern "C" 暴露了一个 C 风格接口 call_cpp_function
  • C 代码通过 extern 声明并调用该 C++ 函数,而实际的功能是在 C++ 动态库中执行的。

3. 讨论:C 和 C++ 动态库的跨语言调用原理

动态库的基本概念:
  • 动态库(Dynamic Link Library,DLL 或 .so 文件)是一种包含可执行代码和数据的文件,它在程序运行时被加载到内存中,并且可以在多个程序之间共享。
  • 当程序需要使用动态库中的函数时,它会通过库文件的路径查找并加载所需的符号(函数或数据)。
extern "C" 的作用:
  • C++ 编译器会对函数进行名称修饰(name mangling),以支持函数重载等特性。而 C 编译器不会做名称修饰。
  • 使用 extern "C" 关键字可以避免 C++ 编译器对函数名进行名称修饰,使得 C 编译器能够正确地找到并调用这些 C++ 函数。
如何跨语言调用:
  1. C 调用 C++ 函数:通过将 C++ 函数封装成 C 风格接口(即不使用类和成员函数的简单函数),然后通过动态库在 C 语言中调用它。这种方式保证了 C 语言能够理解 C++ 函数接口。

  2. C++ 调用 C 函数 :C 语言提供的函数没有 C++ 的名称修饰,C++ 可以通过 extern "C" 声明并直接调用 C 函数。

动态库加载与链接:
  • 静态链接:编译时将函数和库文件直接集成到最终的可执行文件中,生成的程序更大且更新困难。
  • 动态链接:程序在运行时加载动态库,能够节省内存并共享功能模块,同时支持库的独立更新。

总结

  1. C 封装为动态库 :我们将一个简单的 C 函数封装成动态库(如 .so.dll),然后通过 extern "C" 在 C++ 中调用。

  2. C++ 封装为动态库:我们将一个简单的 C++ 类和函数封装成动态库,并提供 C 风格的接口供 C 语言调用。

  3. 跨语言调用 :通过 extern "C" 关键字,C++ 可以调用 C 函数,C 也可以通过 C 风格接口调用 C++ 函数。动态库使得跨语言调用更加灵活和高效。

相关推荐
Xiao Xiangζั͡ޓއއ11 分钟前
程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图<1>
c语言·开发语言·程序人生·学习方法·改行学it
汪款学嵌入式19 分钟前
C语言常用字符串处理函数
c语言
Hunter_pcx30 分钟前
[C++技能提升]插件模式
开发语言·c++
左手の明天1 小时前
【C/C++】C++中使用vector存储并遍历数据
c语言·开发语言·c++
PaLu-LI1 小时前
ORB-SLAM2源码学习:Initializer.cc(13): Initializer::ReconstructF用F矩阵恢复R,t及三维点
c++·人工智能·学习·线性代数·ubuntu·计算机视觉·矩阵
呆呆珝1 小时前
RKNN_C++版本-YOLOV5
c++·人工智能·嵌入式硬件·yolo
.晚街听风~1 小时前
【无标题】
c语言
c++初学者ABC2 小时前
蓝桥杯LQ1044 求完数
c++·算法·lq蓝桥杯
_GR3 小时前
2013年蓝桥杯第四届C&C++大学B组真题及代码
c语言·数据结构·c++·算法·蓝桥杯
CodeClimb3 小时前
【华为OD-E卷 - VLAN资源池 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od