来自Python的C / C ++(增强功能)

主要的

关于如何从Python3调用C / C ++的系列文章中的最后一篇文章,通过所有已知的方法进行了介绍。 这次我得加油 。 下文介绍了这些内容。


ç


我以测试库的相同示例为基础,并使其成为特定方法的变体。 一个测试库,用于演示如何使用带有各种类型参数的全局变量,结构和函数。


test.c:


#include "test.hpp" int a = 5; double b = 5.12345; char c = 'X'; int func_ret_int(int val) { printf("C get func_ret_int: %d\n", val); return val; } double func_ret_double(double val) { printf("C get func_ret_double: %f\n", val); return val; } object func_ret_str(char *val) { printf("C get func_ret_str: %s\n", val); return object(string(val)); } char func_many_args(int val1, double val2, char val3, short val4) { printf("C get func_many_args: int - %d, double - %f, char - %c, short - %d\n", val1, val2, val3, val4); return val3; } test_st_t * func_ret_struct(test_st_t *test_st) { if (test_st) { printf("C get test_st: val1 - %d, val2 - %f, val3 - %c\n", test_st->val1, test_st->val2, test_st->val3); } return test_st; } // _test    BOOST_PYTHON_MODULE(_test) { /* *   */ def("func_ret_int", func_ret_int); def("func_ret_double", func_ret_double); def("func_ret_str", &func_ret_str); def("func_many_args", func_many_args); //   // manage_new_object C     // reference_existing_object C     def("func_ret_struct", &func_ret_struct, return_value_policy<reference_existing_object>()); /* *    */ scope().attr("a") = a; scope().attr("b") = b; scope().attr("c") = c; /* *  */ class_<test_st_t>("test_st_t") .def_readwrite("val1", &test_st_t::val1) .def_readwrite("val2", &test_st_t::val2) .def_readwrite("val3", &test_st_t::val3) ; } 

test.h:


 using namespace boost::python; using namespace std; #ifdef __cplusplus extern "C" { #endif typedef struct test_st_s test_st_t; typedef char * char_p; extern int a; extern double b; extern char c; int func_ret_int(int val); double func_ret_double(double val); object func_ret_str(char *val); char func_many_args(int val1, double val2, char val3, short val4); test_st_t *func_ret_struct(test_st_t *test_st); struct test_st_s { int val1; double val2; char val3; }; #ifdef __cplusplus } #endif 

如何编译:


 g++ -g -fPIC -I/usr/include/python3.6 -I./src/c -o ./objs/test.o -c ./src/c/test.cpp g++ -fPIC -g -shared -o ./lib/_test.so ./objs/test.o -lboost_python3 

源代码编译成一个动态库。
python boostpybind11的用法相似,您还需要描述python将看到的功能。 但我认为,提振更为庞大和复杂。 例如:


 def("func_ret_struct", &func_ret_struct, return_value_policy<reference_existing_object>()); 

func_ret_struct函数将指向结构的指针作为参数,并返回相同的指针。 为此,您需要指定返回对象的规则return_value_policy <reference_existing_object>() 。 reference_existing_objec说返回的对象已经存在。 如果指定manage_new_object,则意味着我们正在返回一个新对象。 在这种情况下,这样的脚本将在垃圾回收器上陷入分段错误


 test_st = _test.test_st_t() ret = _test.func_ret_struct(test_st) 

因为垃圾收集器将首先清除test_st包含的数据,然后再清除ret对象包含的数据。 其中包含与test_st包含的数据相同的数据,但已被清除。


在这种情况下,如何描述这样的功能(不深入)很有趣?:


 test_st_t * func_ret_struct(test_st_t *test_st) { if (test_st) { return test_st; } else { return (test_st_t *) malloc(sizeof(test_st_t)); } } 

这样的函数既可以返回现有对象,也可以返回现有对象。


我也有这样的功能的问题:


 char * func_ret_str(char *val) { return val; } 

据我了解,您无法在boost中从python获得指向标准数据类型的指针。 只能在structclassunion上使用 。 如果有人知道开悟的方法。


巨蟒


对于python,该模块变为本机。
main.py:


 #!/usr/bin/python3 #-*- coding: utf-8 -*- import sys import time #    test #sys.path.append('.') sys.path.append('lib/') #   import _test ### ## C ### print("boost\n") print("C\n") start_time = time.time() ## #    ## print('  :') print('ret func_ret_int: ', _test.func_ret_int(101)) print('ret func_ret_double: ', _test.func_ret_double(12.123456789)) print('ret func_ret_str: ', _test.func_ret_str('Hello!')) print('ret func_many_args: ', _test.func_many_args(15, 18.1617, 'X', 32000)) ## #    ## print('\n  :') print('ret a: ', _test.a) #   . _test.a = 22 print('new a: ', _test.a) print('ret b: ', _test.b) print('ret c: ', _test.c) ## #    ## print('\n  :') #      test_st = _test.test_st_t() test_st.val1 = 5 test_st.val2 = 5.1234567 test_st.val3 = 'Z' print('val1 = {}\nval2 = {}\nval3 = {}'.format(test_st.val1, test_st.val2, test_st.val3)) ret = _test.func_ret_struct(test_st) #    C print('ret val1 = {}\nret val2 = {}\nret val3 = {}'.format(ret.val1, ret.val2, ret.val3)) #   print("--- {} seconds ---".format(time.time() - start_time)) 

提升的利弊


优点


  • 在Python中使用时的简单语法

缺点


  • 您需要编辑C ++源,或为它们编写绑定
  • 单靠提升并不容易

像往常一样,该代码试图清晰地注释。


每个方法从1000开始的平均测试执行时间为:


  • ctypes:-0.0004987692832946777秒-
  • CFFI:-0.00038521790504455566秒-
  • pybind:-0.0004547207355499268秒-
  • C API:-0.0003561973571777344秒-
  • 提升:-0.00037789344787597656秒-

参考文献


Source: https://habr.com/ru/post/zh-CN471618/


All Articles