Python通过Ctypes调用C++类,实测有效

前言

在软件开发中,有时候需要Python与C++相结合,以充分发挥两者的优势 。Python作为一种高级编程语言,具有简洁易读的特点,适用于快速开发和原型设计。而C++则是一种性能强大的编程语言,适用于需要高效率和底层控制的场景。

Python调用C++代码的主要方式是使用Cython、ctypes或SWIG等工具 。其中,Cython是一种混合语言,允许将Python代码与C语言结合,通过编写类型声明来提高性能。而ctypes是Python标准库中的一部分,允许Python直接调用C函数,并处理C数据类型。另外,SWIG(Simplified Wrapper and Interface Generator)是一个自动生成Python和其他语言之间的接口代码的工具,使Python可以调用C++代码。

在实际应用中,Python调用C++的场景包括但不限于:加速Python程序的关键部分、调用现有的C++库以利用其功能、优化某些算法以提高性能等。通过将Python与C++相结合,开发人员可以在保持Python代码易读性和开发效率的同时,充分发挥C++的性能优势,实现更加复杂和高效的应用程序。

Python通过ctypes调用C++代码是一种常见的技术,它提供了一种简单而直接的方法,让Python与C++进行交互。ctypes是Python标准库的一部分,允许Python代码调用动态链接库(DLL)中的C函数,并处理C数据类型。虽然ctypes主要设计用于调用C函数,但也可以用于调用C++代码,只需注意一些特殊的注意事项。

要在Python中通过ctypes调用C++代码,首先需要确保将C++代码编译为动态链接库,以便Python能够加载并调用其中的函数。然后,需要在Python中定义与C++函数相对应的函数原型,并在调用时传递正确的参数和返回类型。此外,需要注意C++代码中的名称修饰(name mangling)以及C++异常处理等问题,确保与Python的交互能够顺利进行。

在实际应用中,Python通过ctypes调用C++代码的场景包括但不限于:利用现有的C++库实现特定功能、加速Python程序的关键部分、与C++库进行交互以实现复杂的功能等。通过使用ctypes,开发人员可以在Python中利用C++的性能优势,同时保持Python代码的简洁性和易读性。

然而,虽然ctypes提供了一种方便的方法来调用C++代码,但它并不是最高效的方法,特别是对于复杂的数据结构和函数签名而言。对于更复杂的场景,可以考虑使用Cython或SWIG等工具,它们提供了更强大和灵活的功能,以便更好地集成Python和C++代码。

因此,Python通过ctypes调用C++代码是一种简单而有效的方法,适用于许多场景。通过正确地处理数据类型和函数签名,并注意到C++与Python之间的差异,开发人员可以轻松地在两种语言之间进行交互,实现更加强大和灵活的应用程序。

创建vs dll工程

在这里插入图片描述

在这里插入图片描述

添加外部库

参考:
vs2019添加使用外置库的设置

编辑代码

添加自己写的C++类

在这里插入图片描述

Foo.h

#pragma once
#ifndef _pro_header_  
#define _pro_header_ 

#ifdef EXPORT_PRO_DLL //如果引用此头文件有预定义为 EXPORT_PRO_DLL
#define PRO_API __declspec(dllexport)  
#else  
#define PRO_API __declspec(dllimport)  
#endif  


class Foo
{
public:
    Foo(int n);
    ~Foo();
    void bar();
    double add(double x);
    int* foobar(int n);
private:
    int val;
};

extern "C"
{
    PRO_API Foo* Foo_new(int n);
    PRO_API void Foo_bar(Foo* foo);
    PRO_API int* Foo_foobar(Foo* foo, int n);
    PRO_API double Foo_add(Foo* foo, double x);

    PRO_API void del_Foo(Foo* foo);
}

#endif 

Foo.cpp

#define EXPORT_PRO_DLL

#include "pch.h"
#include "Foo.h"

#include "string.h"
#include<iostream>

using namespace std;

Foo::Foo(int n)
{
    this->val = n;
}
void Foo::bar()
{
    std::cout << "Value is " << this->val << std::endl;
}
Foo::~Foo()
{
    cout << "delete foo" << endl;
}

int* Foo::foobar(int n)
{
    int* data = new int[2];
    data[0] = 1 + n;
    data[1] = 2 + n;
    return data;
}

double Foo::add(double x)
{
    return x + this->val;
}

void del_Foo(Foo* foo)
{
    delete foo;
}

Foo* Foo_new(int n)
{
    return new Foo(n);
}

void Foo_bar(Foo* foo)
{
    foo->bar();
}

int* Foo_foobar(Foo* foo, int n) {
    return foo->foobar(n);
}

double Foo_add(Foo* foo, double x)
{
    return foo->add(x);
}

编译

在这里插入图片描述

测试

from ctypes import *
import numpy as np

lib = cdll.LoadLibrary(r"路径\Foo\x64\Debug\Foo.dll")

class Foo(object):
    def __init__(self, n):
        lib.Foo_new.argtypes = [c_int]
        lib.Foo_new.restype = c_void_p
        lib.Foo_bar.argtypes = [c_void_p]
        lib.Foo_bar.restype = c_void_p
        lib.Foo_foobar.argtypes = [c_void_p, c_int]
        lib.Foo_foobar.restype = POINTER(c_int)

        lib.Foo_add.argtypes = [c_void_p, c_double]
        lib.Foo_add.restype = c_double

        lib.del_Foo.argtypes = [c_void_p]
        lib.del_Foo.restype = c_void_p

        self.obj = lib.Foo_new(n)

    def __del__(self):
        lib.del_Foo(self.obj) # 析构函数

    def bar(self):
        lib.Foo_bar(self.obj)

    def add(self, x):
        return lib.Foo_add(self.obj, x)

    def foobar(self, n):
        return lib.Foo_foobar(self.obj, n)

if __name__ == '__main__':
    f = Foo(5)
    f.bar()

    data_addr = f.foobar(5)
    array = np.ctypeslib.as_array(data_addr, shape=(2,)) # 不能通过len计算一维数组的元素个数,进一步需要通过函数传过来
    print(array)

    print(f.add(12))

在这里插入图片描述

Ctypes类型

注意:字符串、数组和自定义数据类型需要通过地址来实现C和Python之间的数据传递,其他数据看下表。
Tips:用数据类型的视角去看C++的类,那么类中的方法或者属性可以看成函数中的函数。

在这里插入图片描述

参考

Python调用C/C++的两种方法

官方:扩展和嵌入 Python 解释器

【知识分享】C++与Python联合编程(上)

【知识分享】C++与Python联合编程(下)

使用ctypes在Python中调用C++动态库

Python ctypes:在 C 和 Python 之间传送一维数组

Python ctypes:在C和Numpy之间传送多维数组

  • 11
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
下面是一个简单示例,演示如何在 Python 中使用 `ctypes` 调用 C++ 编写的 DLL 文件: 1. 创建 C++ DLL 文件 首先,您需要创建一个 C++ 动态链接(DLL)文件,其中包含您想要在 Python 中使用的 C++ 函数。下面是一个简单的示例,演示如何在 Visual Studio 中创建一个简单的 DLL 文件: ```cpp // SampleDLL.cpp #include "pch.h" #include "SampleDLL.h" extern "C" { int add(int x, int y) { return x + y; } } ``` 请注意,我们使用 `extern "C"` 来告诉编译器使用 C 语言的函数命名规则,以便在 Python调用。 2. 编译 DLL 文件 使用 Visual Studio,您可以将上述代码编译为 DLL 文件。在生成 DLL 文件之前,您需要将项目属性中的运行设置为“多线程 DLL (/MD)”。 3. 在 Python 中使用 ctypes 调用 DLL 在 Python 中,您可以使用 `ctypes` 模块来调用 DLL 中的函数。下面是一个简单的示例: ```python import ctypes # 加载 DLL 文件 sample_dll = ctypes.CDLL('SampleDLL.dll') # 调用 DLL 中的函数 result = sample_dll.add(1, 2) # 输出结果 print(result) ``` 在上面的示例中,我们首先使用 `ctypes.CDLL()` 函数加载 DLL 文件。然后,我们可以使用 `sample_dll.add()` 来调用 DLL 文件中的 `add()` 函数。最后,我们输出了结果。 请确保在加载 DLL 文件时使用正确的文件名和路径。如果 DLL 文件不在当前工作目录中,则需要指定完整路径。 希望这个示例能够帮助您了解如何在 Python 中使用 `ctypes` 调用 C++ 编写的 DLL 文件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

维度攻城狮

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

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

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

打赏作者

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

抵扣说明:

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

余额充值