关注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函数。
领取专属 10元无门槛券
私享最新 技术干货