【问题标题】:Pass python list to C/C++ as 'float*' or 'int*'将 python 列表作为“float*”或“int*”传递给 C/C++
【发布时间】:2019-02-22 08:37:48
【问题描述】:

C/C++

void func(float* xyz1, float* xyz2,int n){
     //do something
     for(int i=0; i<n;i++){
        printf("%f %f\n",xyz1[i],xyz2[i]);
     }
}

Python

import numpy as np
n = 1000000
xyz1 = np.random.random((n,)).tolist()
xyz2 = np.random.random((n,)).tolist()

#pass above array to the C/C++ code for further processing.
func(xyz1,xyz2,n) # <-- the call to the c/c++ code

我见过使用更高级数据结构(如 C++ 的array)调用 C++ 代码的示例。但是,我只是想使用 int 和 float * 等基本数据类型来传递它

有什么简单的方法,比如 PyBind11 或 python 的内置 C 类型?

【问题讨论】:

标签: python c++ python-3.x ctypes pybind11


【解决方案1】:

您可以通过ctypes 实现此目的。首先使用 C Api 创建一个共享对象。ctypes 不支持 C++,而只支持 C。这意味着您可以在源代码中使用 c++,但您必须提供一个没有 C++ 语言功能(如函数重载或名称修改)的 C 接口。因此函数定义用extern "C"标记。

然后在python中加载共享对象。设置参数类型和结果类型。最后你可以调用你的函数。这是一个例子:

import ctypes
import numpy as np

n = 1000000
xyz1 = np.random.random((n,)).tolist()
xyz2 = np.random.random((n,)).tolist()

#pass above array to the C/C++ code for further processing.
Func = ctypes.CDLL("path/to/libFunc.so")
Func.func.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
res = Func.func(xyz1,xyz2,n) # <-- the call to the c/c++ code

我没有测试它,所以可能有一些错误,但我认为这个想法应该很清楚。这是我测试的一个例子:

CMakeLists.txt:

cmake_minimum_required (VERSION 3.5.1) 
project (DotProduct) 
set(CMAKE_CXX_STANDARD 14) 
set(CMAKE_BUILD_TYPE Debug) 

add_library(DotProduct SHARED src/DotProduct.cpp src/DotProduct.h)

DotProduct.h:

extern "C" double dotProduct(double* l, double* r, unsigned int len);

DotProduct.cpp:

#include "DotProduct.h" 

double dotProduct(double *l, double *r, unsigned int len) { 
    double sum(0); 

    while (len--) { 
        sum += l[len] * r[len]; 
    } 
    return sum; 
}

main.py:

import ctypes

def dot_product(v1, v2):    
    l = len(v1)    
    if l != len(v2):        
        return 0    
    vec1 = (ctypes.c_double * l)(*v1)    
    vec2 = (ctypes.c_double * l)(*v2)    
    Dot_Product = ctypes.CDLL("build/lib/libDotProduct.so")      
    Dot_Product.dotProduct.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_uint]    
    Dot_Product.dotProduct.restype = ctypes.c_double
    return Dot_Product.dotProduct(vec1, vec2, l)

vec1 = [2, 2]
vec2 = [2, 3]
print("{} * {} = {}".format(vec1, vec2, dot_product(vec1, vec2)))

【讨论】:

  • 次要点:在您的工作示例中,您声明了 dotProduct C++ 函数以采用无符号整数。但是在 python 中,你声明它需要一个c_int(一个有符号的整数)。应该是c_uint。再强调一下具有 C 链接和 C++ 链接的函数之间的区别也没有什么坏处。我不知道 OP 和未来的读者会如何意识到这种差异。
  • 感谢 Thomas,使用您的示例并结合编译命令和我在这里读到的“extern c”指令:stackoverflow.com/questions/145270/calling-c-c-from-python,我能够让它工作。
猜你喜欢
  • 2020-11-19
  • 1970-01-01
  • 2020-10-09
  • 1970-01-01
  • 2011-03-16
  • 2021-11-03
  • 2021-12-06
  • 2019-08-30
相关资源
最近更新 更多