C与python混合编程

关注NCUT的信安小哥哥们

一起聊聊python那些实用的话题

大家好我是Lt.今天为大家带来python与C\C++混合编程,python作为一款公认胶水语言混合编程是其必修课,在此通过此贴介绍一下python与C\C++混合编程用到的接口与用法。

0x00 给我一个理由

python的编程效率那么高,我们为什么还要用C\C++呢。

一、如果你要添加/额外的(非Python)功能,提供Python核心功能中没有提供的部分,比如创建新的数据类型或者将Python嵌入到其它已经存在的应用程序中,就要自己去写了,但这还不是最主要的

二、python程序性能瓶颈的效率提升, python作为解释型语言一般比编译型语言慢,想要提高性能,全部改写成编译型语言并不划算,好的做法是,先做性能测试,找出性能瓶颈部分,然后把瓶颈部分在C\C++的扩展中实现,是一个比较简单有效的做法。

三、保持专有源代码的私密,脚本语言一个共同的缺陷是,都是执行的源代码,保密性便没有了。把一部分的代码从Python转到编译语言就可以保持专有源代码私密性。不容易被反向工程,对涉及到特殊算法,加密方法,以及软件安全时,这样做就显得很重要。另一种对代码保密的方式是只发布预编译后的.pyc文件,是一种折中的方法。

0x01搞事

python的混合编程工具有很多,这里主要介绍python自带的ctypes模块。

ctypes模块通过调用动态C的链接库来实现混合。动态链接库即 Windows 下的 .dll 文件,或者 Linux 下的 .so 文件,我们先来了解下python如何调用C的标准库。C的标准库文件在windows下为 msvcrt.dll,一般在目录system32或SYSWOW64下。在linux下是libc.so.6,可以用find / -name libc.so.6找一下。

import platform

from ctypes import *

if platform.system() == 'Windows':

libc = cdll.LoadLibrary('msvcrt.dll')

elif platform.system() =='Linux':

libc = cdll.LoadLibrary('libc.so.6')

libc.printf('Hello ctypes!\n')

这段代码使用标准库的printf打印一条消息。

接下来我们用gcc编译一个自己的动态链接库,C代码如下:

#include

#include

int foo(int a, int b)

{

printf("you input %d and %d\n", a, b);

return a+b;

}

linux下键入gcc -o libpycall.so -shared -fPIC pycall.c命令

python调用代码如下:

import ctypes

ll = ctypes.cdll.LoadLibrary

lib = ll("./libpycall.so")

lib.foo(1, 3)

如果调用C++类的动态链接库,所涉及的C代码需要extern"C"来辅助也就是说只能调用C函数,不能直接调用方法,但能解析通过。

来一个:

//C++

#include

using namespace std;

class TestLib

{

public:

void display();

void display(int a);

};

void TestLib::display() {

cout

}

void TestLib::display(int a) {

cout

}

extern "C" {

TestLib obj;

void display() {

obj.display();

}

void display_int() {

obj.display(2);

}

}

编译命令:g++ -o libpycallclass.so -shared -fPIC pycallclass.cpp

#python的C++调用

import ctypes

so = ctypes.cdll.LoadLibrary

lib = so("./libpycallclass.so")

print 'display()'

lib.display()

print 'display(100)'

lib.display_int(100)

在windows环境下则使用vs2017生成DLL库

在程序第一行加入

#define EXPORT __declspec(dllexport)

再使用ctypes.cdll.LoadLibrary("PATH/some_Dll.dll")调用。

0x02反着来行不行

行啊~

最简单的

#include

int function_of_python(int a)

{

int res;

PyObject *pModule,*pFunc;

PyObject *pArgs, *pValue;

// import

pModule = PyImport_Import(PyString_FromString("some_module"));

// some_module.some_function

pFunc = PyObject_GetAttrString(pModule, "some_function");

// build args

pArgs = PyTuple_New(1);

PyTuple_SetItem(pArgs,0, PyInt_FromLong(a));

//调用

pValue = PyObject_CallObject(pFunc, pArgs);

res = PyInt_AsLong(pValue);

return res;

}

int main(int argc, char *argv[ ])

{

Py_Initialize();

printf("%d",function_of_python(2));

Py_Finalize();

}

在C中所有python元素都是PyObject类型的变量,使用一系列python.h函数进行赋值。PyTuple_New(1)创建了一个新的Tuple变量,a[i] = b对应于PyTuple_SetItem(a,i,b)

最后Python类型A转换为C语言类型B要使用PyA_AsB函数;C类型B转换为Python类型A要使用PyA_FromB函数。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180829G14XHC00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券