
Python调用C/C++动态链接库的需求
在自动化测试过程中,难免会遇到语言混合使用的情况,这不,我们也遇到了。初步决定采用Robot Framework作为自动化测试框架后,其支持Java和Python,而Python作为主流的语言,怎么能放弃使用它的机会^_^。 然而产品采用是古老90年代开发的C/S结构,因为古老,当时也没有考虑到对产品的测试进行自动化,Client端并没有预留CLI(Command Line interface)形式的接口,真是雪上加霜啊。
那怎么自动化?采用AutoIT来对客户端界面进行自动化测试?可惜AutoIT对当初开发采用的控件识别不是很好,如果采用控件所在位置来进行控制的方式,又会导致自动化测试并不是很稳定。那么!!!只有自己开发接口了,目前在Client端开发出CLI形式的接口,将其封装为DLL,然后在Robot FrameWork框架中采用Python对DLL进行调用。任务艰巨哪!
Python调用DLL例子
示例一
首先,在创建一个DLL工程(本人是在VS 2005中创建),头文件:
[cpp] view plain copy 在CODE上查看代码片派生到我的代码片//helloh
#ifdef EXPORT_HELLO_DLL
#define HELLO_API __declspec(dllexport)
#else
#define HELLO_API __declspec(dllimport)
#endif
extern "C"
{
HELLO_API int IntAdd(int , int);
}
CPP文件:
[cpp] view plain copy 在CODE上查看代码片派生到我的代码片//hellocpp
#define EXPORT_HELLO_DLL
#include "helloh"
HELLO_API int IntAdd(int a, int b)
{
return a + b;
}
这里有两个注意点:
(1)弄清楚编译的时候函数的调用约定采用的__cdecl还是__stdcall,因为根据DLL中函数调用约定方式,Python将使用相应的函数加载DLL。
(2)如果采用C++的工程,那么导出的接口需要extern "C",这样python中才能识别导出的函数。
我的工程中采用__cdecl函数调用约定方式进行编译链接产生hellodll,然后Python中采用ctypes库对hellodll进行加载和函数调用:
[python] view plain copy 在CODE上查看代码片派生到我的代码片from ctypes import
dll = cdllLoadLibrary('hellodll');
ret = dllIntAdd(2, 4);
print ret;
OK,一个小例子已经完成了,如果你感兴趣,但还没试过,那就尝试一下吧。
示例二
示例一只是一个"hello world"级别的程序,实际运用中更多的需要传递数据结构、字符串等,才能满足我们的需求。那么这个示例将展示,如何传递数据结构参数,以及如何通过数据结构获取返回值。
首先编写DLL工程中的头文件:
[cpp] view plain copy 在CODE上查看代码片派生到我的代码片//helloh
#ifdef EXPORT_HELLO_DLL
#define HELLO_API __declspec(dllexport)
#else
#define HELLO_API __declspec(dllimport)
#endif
#define ARRAY_NUMBER 20
#define STR_LEN 20
struct StructTest
{
int number;
char pChar;
char str[STR_LEN];
int iArray[ARRAY_NUMBER];
};
extern "C"
{
//HELLO_API int IntAdd(int , int);
HELLO_API char GetStructInfo(struct StructTest pStruct);}
CPP文件如下:
[cpp] view plain copy 在CODE上查看代码片派生到我的代码片//hellocpp
#include <stringh>
#define EXPORT_HELLO_DLL
#include "helloh"
HELLO_API char GetStructInfo(struct StructTest pStruct){
for (int i = 0; i < ARRAY_NUMBER; i++)
pStruct->iArray[i] = i;
pStruct->pChar = "hello python!";
strcpy (pStruct->str, "hello world!");
pStruct->number = 100;
return "just OK";
}
GetStructInfo这个函数通过传递一个StructTest类型的指针,然后对对象中的属性进行赋值,最后返回"just OK"
编写Python调用代码如下,首先在Python中继承Structure构造一个和C DLL中一致的数据结构StructTest,然后设置函数GetStructInfo的参数类型和返回值类型,最后创建一个StructTest对象,并将其转化为指针作为参数,调用函数GetStrcutInfo,最后通过输出数据结构的值来检查是否调用成功:
[python] view plain copy 在CODE上查看代码片派生到我的代码片from ctypes import
ARRAY_NUMBER = 20;
STR_LEN = 20;
#define type
INTARRAY20 = c_int ARRAY_NUMBER;
CHARARRAY20 = c_char STR_LEN;
#define struct
class StructTest(Structure):
_fields_ = [
("number", c_int),
("pChar", c_char_p),
("str", CHARARRAY20),
("iArray", INTARRAY20)
]
#load dll and get the function object
dll = cdllLoadLibrary('hellodll');
GetStructInfo = dllGetStructInfo;
#set the return type
GetStructInforestype = c_char_p;
#set the argtypes
GetStructInfoargtypes = [POINTER(StructTest)];objectStruct = StructTest();
#invoke api GetStructInfo
retStr = GetStructInfo(byref(objectStruct));#check result
print "number: ", objectStructnumber;
print "pChar: ", objectStructpChar;
print "str: ", objectStructstr;
for i,val in enumerate(objectStructiArray):
print 'Array[i]: ', val;
print retStr;
总结
1 用64位的Python去加载32位的DLL会出错
2 以上只是些测试程序,在编写Python过程中尽可能的使用"try Except"来处理异常3 注意在Python与C DLL交互的时候字节对齐问题4 ctypes库的功能还有待继续探索
python和c语言的区别主要体现在:语言类型;内存管理;速度;应用;运行;对象;声明;测试和调试难度;复杂度;学习程度。
语言类型Python是一运首纯种基于解释器的,面向对象的解释型语言。解释器会逐行读取代码;首先将Python编运首纯译为字节码,然后由大型C程序解释。 C是一种面向过程的编译型语言,完整的源代码将旁芹坦咐直接运首纯编译为机器代码,由CPU直接执行。
Python是一种动态类型语言,又是强类型语言。它们确定一个变量的类型是在您第一次给它赋值的时候。C 是静态类型语言,一种在编译期间就确定数据类型的语言芹坦。大多数静态类型语言是通过要求在使用任一变量之前声明其数据类型来保证这一点的。
其他区别:
Python中所有的数据,都是由对象或者对象之间的关系芹坦表示的,函数是对象,字符串是对象,每个东西都是对象的概念。每一个对象都有三种属性: 实体,类型和值。
C中没有对象这个概念,只有“数据的表示”,比如说,如果有两个int变量a和b,想旁咐比较大小,可以用a == b来判断,但是如果是两个旁咐字符串变量a和b,就不得不用strcmp库函数来比较了,因为此时,a和b本质上是指向字符串的指针,如果直接用==比较, 那比较的实际是指针中存储的值地址。
import time
str='Hi,guys\n'
for letter in str:
print(letter)
timesleep(05)
注意最后两行缩进,百度知道回答完没有缩进
python源程序执行的方式如下:
1、在命令行输入ipython或ipython3进入交互式shell环境,如果不行的话需要安装ipython和python镜像,配置方式:pip3 install ipython -i ctrl+D或者exit 推出ipython ipython的优点:支持自动补全和执行linux命令。
2、在命令行窗口输入python (官方的shell),在这里可以直接输入python程序代码,退出用exit() 或者 ctrl+D。
3、集成开发环境:PyCharm 类似IDEA,推荐教程: 《Python教程》。
编译执行
所谓编译执行就是源代码经过编译器编译处理,生成目标机器码,就是机器能直接运行的二进制代码,下次运行时无需重新编译。不过它是针对特定CPU体系的,这些目标代码只能在特定平台执行。
如果这个程序需要在另外一种 CPU 上面运行,这个代码就必须重新编译。它不具备可移植性,但是执行速度快,C、C++这类语言属于编译型语言。
C语言和Python语言虽然均可用于编写计算机程序,但它们在执行方式上略有不同。C语言是一种编译型语言,程序需要先经过编译器的编译过程,将源代码转换为机器语言,在计算机上运行时直接执行机器语言程序。与之不同,Python是一种解释型语言,可以直接执行Python程序,无需先按照C语言那样进行编译。Python解释器将Python代码作为输入,边解释边执行,直到程序结束。相比较而言,编译型语言的程序一般更高效,但执行之前需要额外的编译过程;而解释型语言的程序则更加灵活,但需要消耗更多的计算资源。
这个思路不是很行得通。。建议题主再思考一下程序结构。
为何要在C程序中嵌入python呢?
windows下,如果是一个独立的python脚本,可以用py2exe转换成一个可独立运行的exe。因此如果能把python代码分离出来,问题就简单了。
Python指它的标准实现,即CPython(虽然不是很严格)
本文分4个部分
C/C++ 调用 Python (基础篇)— 仅讨论Python官方提供的实现方式
Python 调用 C/C++ (基础篇)— 仅讨论Python官方提供的实现方式
C/C++ 调用 Python (高级篇)— 使用 Cython
Python 调用 C/C++ (高级篇)— 使用 SWIG
练习本文中的例子,需要搭建Python扩展开发环境。具体细节见搭建Python扩展开发环境 - 蛇之魅惑 - 知乎专栏
1 C/C++ 调用 Python(基础篇)
Python 本身就是一个C库。你所看到的可执行体python只不过是个stub。真正的python实体在动态链接库里实现,在Windows平台上,这个文件位于 %SystemRoot%\System32\python27dll。
你也可以在自己的程序中调用Python,看起来非常容易:
//my_pythonc
#include <Pythonh>
int main(int argc, char argv[])
{
Py_SetProgramName(argv[0]);
Py_Initialize();
PyRun_SimpleString("print 'Hello Python!'\n");
Py_Finalize();
return 0;
}
在Windows平台下,打开Visual Studio命令提示符,编译命令为
cl my_pythonc -IC:\Python27\include C:\Python27\libs\python27lib
在Linux下编译命令为
gcc my_pythonc -o my_python -I/usr/include/python27/ -lpython27
在Mac OS X 下的编译命令同上
产生可执行文件后,直接运行,结果为输出
Hello Python!
Python库函数PyRun_SimpleString可以执行字符串形式的Python代码。
虽然非常简单,但这段代码除了能用C语言动态生成一些Python代码之外,并没有什么用处。我们需要的是C语言的数据结构能够和Python交互。
下面举个例子,比如说,有一天我们用Python写了一个功能特别强大的函数:
def great_function(a):
return a + 1
接下来要把它包装成C语言的函数。我们期待的C语言的对应函数应该是这样的:
int great_function_from_python(int a) {
int res;
// some magic
return res;
}
首先,复用Python模块得做‘import’,这里也不例外。所以我们把great_function放到一个module里,比如说,这个module名字叫 great_modulepy
接下来就要用C来调用Python了,完整的代码如下:
#include <Pythonh>
int great_function_from_python(int a) {
int res;
PyObject pModule,pFunc;
PyObject pArgs, pValue;
/ import /
pModule = PyImport_Import(PyString_FromString("great_module"));
/ great_modulegreat_function /
pFunc = PyObject_GetAttrString(pModule, "great_function");
/ build args /
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs,0, PyInt_FromLong(a));
/ call /
pValue = PyObject_CallObject(pFunc, pArgs);
res = PyInt_AsLong(pValue);
return res;
}
从上述代码可以窥见Python内部运行的方式:
所有Python元素,module、function、tuple、string等等,实际上都是PyObject。C语言里 *** 纵它们,一律使用PyObject 。
Python的类型与C语言类型可以相互转换。Python类型XXX转换为C语言类型YYY要使用PyXXX_AsYYY函数;C类型YYY转换为Python类型XXX要使用PyXXX_FromYYY函数。
也可以创建Python类型的变量,使用PyXXX_New可以创建类型为XXX的变量。
若a是Tuple,则a[i] = b对应于 PyTuple_SetItem(a,i,b),有理由相信还有一个函数PyTuple_GetItem完成取得某一项的值。
不仅Python语言很优雅,Python的库函数API也非常优雅。
现在我们得到了一个C语言的函数了,可以写一个main测试它
#include <Pythonh>
int great_function_from_python(int a);
int main(int argc, char argv[]) {
Py_Initialize();
printf("%d",great_function_from_python(2));
Py_Finalize();
}
编译的方式就用本节开头使用的方法。
在Linux/Mac OSX运行此示例之前,可能先需要设置环境变量:
bash:
export PYTHONPATH=:$PYTHONPATH
csh:
setenv PYTHONPATH :$PYTHONPATH
2 Python 调用 C/C++(基础篇)
这种做法称为Python扩展。
比如说,我们有一个功能强大的C函数:
int great_function(int a) {
return a + 1;
}
期望在Python里这样使用:
>>> from great_module import great_function
>>> great_function(2)
3
考虑最简单的情况。我们把功能强大的函数放入C文件 great_modulec 中。
#include <Pythonh>
int great_function(int a) {
return a + 1;
}
static PyObject _great_function(PyObject self, PyObject args)
{
int _a;
int res;
if (!PyArg_ParseTuple(args, "i", &_a))
return NULL;
res = great_function(_a);
return PyLong_FromLong(res);
}
static PyMethodDef GreateModuleMethods[] = {
{
"great_function",
_great_function,
METH_VARARGS,
""
},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initgreat_module(void) {
(void) Py_InitModule("great_module", GreateModuleMethods);
}
除了功能强大的函数great_function外,这个文件中还有以下部分:
包裹函数_great_function。它负责将Python的参数转化为C的参数(PyArg_ParseTuple),调用实际的great_function,并处理great_function的返回值,最终返回给Python环境。
导出表GreateModuleMethods。它负责告诉Python这个模块里有哪些函数可以被Python调用。导出表的名字可以随便起,每一项有4个参数:第一个参数是提供给Python环境的函数名称,第二个参数是_great_function,即包裹函数。第三个参数的含义是参数变长,第四个参数是一个说明性的字符串。导出表总是以{NULL, NULL, 0, NULL}结束。
导出函数initgreat_module。这个的名字不是任取的,是你的module名称添加前缀init。导出函数中将模块名称与导出表进行连接。
安装并配置完成之后,我们就可以编写第一个python程序。学过其他语言的兄弟姐妹们,都知道语言的入门程序就是hello world。那么,我们这里也以hello world来抛砖引玉,打开python学习的大门。
python运行有两种方式,一种是在python交互式命令行下运行;另一种是使用文本编辑器,在命令行中直接运行。
注意:以上两种运行方式,都是以CPython解释器来编译运行的。当然也可以将python代码写入到eclipse中,使用JPython解释器运行,需要自己配置环境。(推荐学习:Python视频教程)
一、命令行与交互式命令行
首先要搞清楚这个命令行的概念。
1命令行
定义:出现类似“C:\>”,则是在Windows提供的命令行模式
进入模式的方式:Windows中,直接win+r键进入
2交互式命令行
定义:出现“>>>”,则是python的交互式命令行
进入模式的方式:Windows命令行中输入python即可
二、交互式命令行中运行python代码
cmd窗口中,输入python后,进入python交互式命令行。直接输入代码:
print ‘hello world!’
python-23png
可以看到界面上运行结果,表示运行成功!
在Python的交互式命令行写程序,好处是一下就能得到结果,坏处是没法保存,下次还想运行的时候,还得再敲一遍。
所以,实际开发的时候,我们总是使用一个文本编辑器来写代码,写完了,保存为一个文件,这样,程序就可以反复运行了。
三、命令行运行python代码
1python代码编写及保存
我们将“hello world!”程序用文本编辑器写出来,保存下来,并命名,这里我们命名为hellopy,保存到F:\workspace。
命名时,要注意:
1)文件要以py结尾,其他都不可以
2)文件名只能是英文字母、数字和下划线的组合。
文本编辑器推荐:Notepad++、Sublime Text
2python代码运行
在命令行模式中,输入python F:\workspace\hellopy,即可运行成功。
运行时,要注意:
1)python文件存储路径是相对路径,运行时,一定要说明python文件的存储路径,
当然,用Python开发程序,完全可以一边在文本编辑器里写代码,一边开一个交互式命令窗口,在写代码的过程中,把部分代码粘到命令行去验证,事半功倍!
以上就是关于python怎么调用c的动态链接库全部的内容,包括:python怎么调用c的动态链接库、python和c语言的区别、C语言这段代码在Python如何实现等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)