2

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

I have seen examples that call the C++ code using more high-level data structures like C++'s array. However, I simply want to pass it using basic data types like int and float *

Any simple way of doing this, with say PyBind11 or python's built-in C types?

sanjeev mk
  • 4,276
  • 6
  • 44
  • 69
  • To execute C++ code in python, you could use boost python. -> https://www.boost.org/doc/libs/1_63_0/libs/python/doc/html/tutorial/index.html – ncica Feb 22 '19 at 08:57

1 Answers1

3

You can achieve this with ctypes. First create a shared object with C Api.ctypes does not support C++ but only C. This means that you can use c++ in your source code but you have to provide a C interface without C++ languages features like function overloading or name mangling. Therefor the function definitions are marked with extern "C".

Then load the shared object in python. Set argument types and result types. Finally you can call your function. Here is an example:

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

I didn't test it so possibly there are some errors but I think the idea should be clear. Here is an example I tested:

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)))
Thomas Sablik
  • 16,127
  • 7
  • 34
  • 62
  • Minor point: In your worked example you declared the `dotProduct` C++ function to take an unsigned int. But in python you state that it takes a `c_int` (a signed int). It should be `c_uint`. It also couldn't hurt to stress the difference between functions with C linkage and C++ linkage a bit more. I don't know how aware OP and future readers will be aware of that difference. – Dunes Feb 22 '19 at 10:18
  • 1
    Thanks Thomas, using your example and combining with the compilation commands and the "extern c" directive I read about here : https://stackoverflow.com/questions/145270/calling-c-c-from-python, I was able to get this working. – sanjeev mk Feb 22 '19 at 10:43