title: Python调用C/C++入门
date: 2019-08-23 14:19:00
categories: 量化交易系统
tags: [ctypes]

1. 背景

最近公司在某券商募集了一笔资金,需要对接其提供的程序化接口方便以后进行交易,对方只提供了c++版本程序,我们系统是python开发的,所以需要用python调用c++,大致了解下了python调用c++的几种方式,下面根据网上的资料介绍下几种方式优缺点,最后给个mac环境下python调用c++的例子。

2. Python调用C/C++程序方法

  1. ctypes

    • 如果是 C 函数库,则直接 load 这个库,然后调用即可;
    • 如果是 C++ 函数库,则需要用extern关键字封装一个供 C 使用的函数,即把类隐藏到一些 C 风格的函数里,然后用 extern 标明这些函数,以方便外部调用。
  2. SWIG

    SWIG完整支持ANSI C,支持除嵌套类外的所有C++特性。SWIG是一个接口编译器,旨在为C/C++方便地提供脚本语言接口。SWIG不仅可以为C/C++程序生成 Python接口,目前可以生成CLISP,Java,Lua,PHP,Ruby,Tcl等19种语言的接口。SWIG被Subversion, wxPython, Xapian等项目使用。值得一提的是,Google也使用SWIG。

  3. SIP

    SIP是一种Python工具,用于自动生成Python与C、C++库的绑定。SIP最初是在1998年用PyQt开发的,用于Python与Qt GUI toolkit的绑定,但适用于生成任何C或C++库的绑定。

  4. Cython

    Cython是让Python脚本支持C语言扩展的编译器,Cython能够将Python+C混合编码的.pyx脚本转换为C代码,主要用于优化Python脚本性能或Python调用C函数库。由于Python固有的性能差的问题,用C扩展Python成为提高Python性能常用方法,Cython算是较为常见的一种扩展方式。

  5. Boost.Python

    Boost.Python是Boost提供的一个C++的模板库,用以支持Python和C++的无缝互操作。相对SWIG来说,这个库的优势是功能通过C++ API完成,不用学习写新的接口文件。对C++的支持更自然、完整。

ctypes SWIG SIP Cython Boost.Python
是否支持Python3 支持 支持 支持 支持 支持
对接难易程度 简单 中等 中等 困难 困难
是否需开发封装代码 c++需要,c不需要 需要 需要 需要 需要

3. 使用ctypes调用C/C++ 例子

3.1 安装 GNU 的 C/C++ 编译器

以mac为例,安装之后命令行输入 g++ -v 查看是否安装成功

1
2
3
4
5
6
 ~/ g++ -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin18.2.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

3.2 开发c++例子程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>     
class Test{
public:
void print(){
std::cout << "Hello world!" << std::endl;
}
};

extern "C" {
Test* Test_new(){
return new Test();
}
void Test_print(Test* test){
test->print();
}
}

保存文件未test.cpp,编译代码生成动态链接库:

1
g++ -o test.so -shared -fPIC test.cpp

执行完成后会在当前目录下生辰test.so 文件

3.3 Python中调用so

1
2
3
4
5
6
7
8
9
10
11
12
from ctypes import cdll
lib = cdll.LoadLibrary('./test.so')

class Test(object):
def __init__(self):
self.obj = lib.Test_new()

def print(self):
lib.Test_print(self.obj)

test = Test()
test.print()

执行Python代码会输出 Hello world!,说明执行成功

参考

https://stackoverflow.com/questions/145270/calling-c-c-from-python

关于python对接c/c++各种方案的优缺点,这篇文章说的比较清楚: https://www.jb51.net/article/63623.htm

我的微信公众号:pyquant