[Python] 如何通过ctypes库来调用C++ 动态库 DLL?

57 篇文章 2 订阅

ctypes库介绍

ctypes是Python的一个外部库,它提供了一种灵活的方式来调用C语言的动态链接库(DLL)或共享库(SO)。通过ctypes,我们可以在Python中直接调用C语言编写的函数和变量,从而实现跨语言的互操作。

ctypes 它提供了与 C 兼容的数据类型,并允许调用 DLL 或共享库中的函数。可使用该模块以纯 Python 形式对这些库进行封装。

ctypes提供的方法和C语言对应的数据类型如下表:

ctypes --- Python 的外部函数库 — Python 3.12.1 文档

ctypes — A foreign function library for Python — Python 3.12.1 documentation

默认情况下都会假定函数返回 C int 类型。 其他返回类型可通过设置函数对象的 restype 属性来指定。

使用ctypes的基本步骤如下:

  1. 导入ctypes库
  2. 加载动态链接库或共享库
  3. 定义函数原型
  4. 调用函数

创建C++ 动态库

如何通过VS 2022创建C++动态连接库,可以阅读:[C++] VS 2022演练 - 创建和使用用动态连接库(DLL) (详细图文)-CSDN博客

这里是我创建好的MathLibrary动态链接库:

 MathLibrary.h

// MathLibrary.h - Contains declarations of math functions
#pragma once

#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif

// The Fibonacci recurrence relation describes a sequence F
// where F(n) is { n = 0, a
//               { n = 1, b
//               { n > 1, F(n-2) + F(n-1)
// for some initial integral values a and b.
// If the sequence is initialized F(0) = 1, F(1) = 1,
// then this relation produces the well-known Fibonacci
// sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

// Initialize a Fibonacci relation sequence
// such that F(0) = a, F(1) = b.
// This function must be called before any other function.
extern "C" MATHLIBRARY_API void fibonacci_init(
    const unsigned long long a, const unsigned long long b);

// Produce the next value in the sequence.
// Returns true on success and updates current value and index;
// false on overflow, leaves current value and index unchanged.
extern "C" MATHLIBRARY_API bool fibonacci_next();

// Get the current value in the sequence.
extern "C" MATHLIBRARY_API unsigned long long fibonacci_current();

// Get the position of the current value in the sequence.
extern "C" MATHLIBRARY_API unsigned fibonacci_index();

备注: 代码中在MATHLIBRARY_API前面必须增加 “ extern "C" ” 前缀,否则会导致ctypes无法找到对应的函数,如下图所示:

在C++中,extern "C"是一个链接指示符,用于告诉编译器按照C语言的方式进行编译。这意味着在C++代码中使用extern "C"声明的函数或变量将被当作C语言的函数或变量进行处理,而不会被当作C++的函数或变量进行处理。

extern "C"的作用主要有以下几点:

  1. 保持函数名和变量名的C语言兼容性。在C++中,函数名和变量名默认会添加前缀“_”,而在C语言中则不会。使用extern "C"可以避免这种情况的发生。

  2. 保持函数参数类型的C语言兼容性。在C++中,函数参数类型可能会被自动推导为模板类型,而在C语言中则不会。使用extern "C"可以避免这种情况的发生。

  3. 保持函数调用约定的C语言兼容性。在C++中,函数调用约定可能会有所不同,如stdcall、cdecl等,而在C语言中则只有一种调用约定。使用extern "C"可以避免这种情况的发生。

  4. 与某些C语言库进行交互。有些C语言库可能不支持C++的名称修饰(name mangling),这时可以使用extern "C"来避免名称修饰带来的问题。

MathLibrary.cpp

// MathLibrary.cpp : Defines the exported functions for the DLL.
#include <utility>
#include <limits.h>
#include "MathLibrary.h"

// DLL internal state variables:
static unsigned long long previous_;  // Previous value, if any
static unsigned long long current_;   // Current sequence value
static unsigned index_;               // Current seq. position

// Initialize a Fibonacci relation sequence
// such that F(0) = a, F(1) = b.
// This function must be called before any other function.
void fibonacci_init(
    const unsigned long long a,
    const unsigned long long b)
{
    index_ = 0;
    current_ = a;
    previous_ = b; // see special case when initialized
}

// Produce the next value in the sequence.
// Returns true on success, false on overflow.
bool fibonacci_next()
{
    // check to see if we'd overflow result or position
    if ((INT_MAX - previous_ < current_) ||
        (20 == index_))
    {
        return false;
    }

    // Special case when index == 0, just return b value
    if (index_ > 0)
    {
        // otherwise, calculate next sequence value
        previous_ += current_;
    }
    std::swap(current_, previous_);
    ++index_;
    return true;
}

// Get the current value in the sequence.
unsigned long long fibonacci_current()
{
    return current_;
}

// Get the current index position in the sequence.
unsigned fibonacci_index()
{
    return index_;
}

构建生成MathLibrary.dll:

python调用C++动态链接库

[Python] Jupyter Notebook(Jupyter Lab)介绍,安装,配置,启动及创建第一个notebook_python 启动jupyter lab-CSDN博客

1)把MathLibarary.dll上传到Jupyter Notebook所在的目录。

2)在Jupyter Notebook中运行下面的Python代码片段。

import ctypes
from ctypes import c_bool
math_dll = ctypes.cdll.LoadLibrary('./MathLibrary.dll')
# Initialize a Fibonacci relation sequence.
math_dll.fibonacci_init(1, 1)

math_dll.fibonacci_next.restype = c_bool

# Write out the sequence values until overflow.
while True:
    print(math_dll.fibonacci_index(), ": ", math_dll.fibonacci_current())
    if not math_dll.fibonacci_next():
        break
# Report count of values written before overflow.
print(math_dll.fibonacci_index() + 1, " Fibonacci sequence values fit in an unsigned 64-bit integer.");

备注:ctypes默认情况下都会假定函数返回 C int 类型。 其他返回类型可通过设置函数对象的 restype 属性来指定,因为fibonacci_next函数返回的是bool值,所以这里需要自己来规定fibonacci_next的返回类型为c_bool,否则会导致fibonacci_next返回的是int,无法进行到break语句。

当然,你也可以直接把上面的代码保存为.py文件,然后放在MathLibrary.dll相同的目录下,直接通过python运行.py文件。

  • 22
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老狼IT工作室

你的鼓励将是我创作的最大动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值