C++ - Python Binding with ctypes - Return multiple values in function

情到浓时终转凉″ 提交于 2019-12-13 01:07:57

问题


I found this example of C++ Python binding: Calling C/C++ from python? According to the answer there, I created some testfiles:

foo.cpp:

#include <iostream>
#include <utility>


int bar_2(int a, int b){
    return a*b;
}

std::pair<int, int> divide(int dividend, int divisor)
{
   return std::make_pair(dividend / divisor, dividend % divisor);
}

extern "C" {
    int bar_2_py(int a, int b){ return bar_2(a,b); }
    std::pair<int, int> divide_py(int d, int div){return divide(d,div);}
}

fooWrapper.py:

#!/usr/bin/env python

from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')

def bar_2(a, b):
    res = lib.bar_2_py( a,b )
    return res

def divide(d,div):
    res = lib.divide_py(d,div)
    return res

Then

g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

creates libfoo.so

If I import it and run the functions in iPython I get the right value for function "bar_2" but a (partly) wrong answer for "divide":

from fooWrapper import bar_2, divide
bar_2(10,2) # returns 20, which is right
divide(10,3) # returns 3

Obviously, the return-value is right for the first value of the pair (as 10/3 int division is 3). But the second value was getting lost.

So, what would be best practice to obtain multiple values (in this case 2 integer values)?

Thank you!


回答1:


I don't think ctypes allows one to translate std::pair to a python tuple without much boilerplate code. Especially since std::pair is a feature of the c++11 standard, and ctypes only works with c-style functions [citation / verification needed].

I suggest would using output parameters, the c way to return multiple values. The idea is simple, the c-function returns it's values by pointer, example.c:

void divide_modulo(int a, int b, int *div, int *rest)
{
    *div  = a / b;
    *rest = a % b;
}

Then compile it to a shared library:

gcc -o libexample.so -shared example.c

The libexample.so now allows you to write to python integers via a pointer in c which are passes as parameters like this:

import ctypes
lib = ctypes.cdll.LoadLibrary('./libexample.so')

def divide_modulo(a, b):
  div = ctypes.c_int(0)
  rest = ctypes.c_int(0)
  lib.divide_modulo(a, b, ctypes.byref(div), ctypes.byref(rest))
  return (div.value, rest.value)

print(divide_modulo(11, 4))

The ctypes.byref wrapper when calling lib.divide_modulo with div and rest converts an int to a pointer to an int.



来源:https://stackoverflow.com/questions/31835398/c-python-binding-with-ctypes-return-multiple-values-in-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!