本文目录一览:
- 1、python怎么导入ctypes
- 2、python 是否有能列出动态链接库中有哪些方法的库
- 3、python ctypes 怎么处理函数返回的一般指针
- 4、关于python ctypes里 Union的问题
- 5、Python 外部函数调用库ctypes简介
python怎么导入ctypes
1. 加载Windows系统自带的dll文件:
#加载cdecl调用约定的dll
msvcrt =cdll.msvcrt
#加载stdcall调用约定的dll
kernel32 =windll.kernel32
2. 加载自己dll文件,假如为addFuncDll,方式如下:
mydll =CDLL("addFuncDll.dll")
或者 mydll = cdll.addFuncDll
如果其中有函数add,计算两个整数的和,则使用方式如下:
result=mydll.add(4,5)
可以多一步指明add函数的参数类型(也可不指明):
mydll.add.argtypes= [c_int,c_int]
3. 结构体在python中定义为Structure的子类如下:
class POINT(Structure):
_fields_ = [("x", c_int),
("y",c_int)]
_fields中每一项为元组(成员名称,类型)
结构体还可以用于其他的结构体:
class RECT(Structure):
_fields_ = [("upperleft",POINT),
("lowerright",POINT)]
python 是否有能列出动态链接库中有哪些方法的库
最近看了《Gray hat python》一书,这才知道为什么python是黑客必学的编程语言。通过python的ctypes模块,可以直接调用动态链接库中的导出函数,而且甚至可以直接在python中构建出复杂的C结构体!!!使得python也具备了底层内存操作的能力,再配合python本身强大的表达能力,能不让人激动么。
之前为了在python中调用动态链接库导出的函数,你需要自行解析出这些导出函数的地址。而现在ctypes库会替我们完成这个麻烦的过程,大大方便了我们直接在python中调用C函数的能力。
ctypes模块中有三种不同的动态链接库加载方式:cdll, windll, oledll。不同之处在于链接库中的函数所遵从的函数调用方式(calling convention)以及返回方式有所不同。
cdll用于加载遵循cdecl标准函数调用约定的链接库。windll则用于加载遵循stdcall调用约定的动态链接库。oledll与windll完全相同,只是会默认其载入的函数会统一返回一个Windows HRESULT错误编码。
先复习一下有关函数调用约定的知识:函数调用约定指的是函数参数入栈的顺序、哪些参数入栈、哪些通过寄存器传值、函数返回时栈帧的回收方式(是由调用者负责清理,还是被调用者清理)、函数名称的修饰方法等等。基本上我们最常见的调用约定就是cdecl和stdcall两种。在《程序员的自我修养--链接、装载与库》一书的第10章有对函数调用约定的更详细介绍。
cdecl规定函数参数列表以从右到左的方式入栈,且由函数的调用者负责清除栈帧上的参数。stdcall的参数入栈方式与cdecl一致,但函数返回时是由被调用者自己负责清理栈帧。而且stdcall是Win32 API函数所使用的调用约定。OK,就这么多,够了。
测试一下在Linux平台和Windows平台下通过ctypes模块导入C库中函数的小例子:
Windows 下:
from ctypes import *
msvcrt = cdll.msvcrt
msg = "Hello world!\n"
msvcrt.printf("Testing: %s", msg)
Linux下:
from ctypes import *
libc = CDLL("libc.so.6")
msg = "Hello, world!\n"
libc.printf("Testing: %s", msg)
可以看到动态链接库中的printf被直接导入到python中来调用了。
那么,在python中怎么表示C的类型?不用担心,下面这张表就能搞定。
有了这个映射关系,多复杂的C类型也能在python中表达出来。
在C中定义一个联合:
union
{
long barley_long;
int barley_int;
char barley_char[8];
}barley_amount;
而在python中同等的定义为:注意一下python中定义数组的方式。
class barley_amount(Union):
_fields_ = [
("barley_long", c_long),
("barley_int", c_int),
("barley_char", c_char * 8),
]
测试一下这个例子,在python中定义一个联合体,为其赋值,再分别访问其成员。
from ctypes import *
class barley_amount(Union):
_fields_ = [
("barley_long", c_long),
("barley_int", c_int),
("barley_char", c_char * 8),
]
value = raw_input("Enter the amount of barley to put into the beer vat:")
my_barley = barley_amount(int(value))
print "Barley amount as a long: %ld" % my_barley.barley_long
print "Barley amount as an int: %d" % my_barley.barley_int
print "Barley amount as a char: %s" % my_barley.barley_char
python ctypes 怎么处理函数返回的一般指针
test.c(动态库源代码)
[cpp] view plain copy
// 编译生成动态库: gcc -g -fPIC -shared -o libtest.so test.c
#include stdio.h
#include string.h
#include stdlib.h
typedef struct StructPointerTest
{
char name[20];
int age;
}StructPointerTest, *StructPointer;
StructPointer test() // 返回结构体指针
{
StructPointer p = (StructPointer)malloc(sizeof(StructPointerTest));
strcpy(p-name, "Joe");
p-age = 20;
return p;
}
编译:gcc -g -fPIC -shared -o libtest.so test.c
call.py(python调用C语言生成的动态库):
[python] view plain copy
#!/bin/env python
# coding=UTF-8
from ctypes import *
#python中结构体定义
class StructPointer(Structure):
_fields_ = [("name", c_char * 20), ("age", c_int)]
if __name__ == "__main__":
lib = cdll.LoadLibrary("./libtest.so")
lib.test.restype = POINTER(StructPointer)
p = lib.test()
print "%s: %d" %(p.contents.name, p.contents.age)
最后运行结果:
[plain] view plain copy
[zcm@c_py #112]$make clean
rm -f *.o libtest.so
[zcm@c_py #113]$make
gcc -g -fPIC -shared -o libtest.so test.c
[zcm@c_py #114]$./call.py
Joe: 20
[zcm@c_py #115]$
关于python ctypes里 Union的问题
DataValue(Structure):
_anonymous_ = ('DataValue',)
可能是写错了,改成:
class DataValue(Structure):
_anonymous_ = ('DataValue',)
data_value.DataValue = 23
这句报错吗?
换成:
data_value.i4Val = 32
试试
如果有问题,希望你把错误的原因(traceback)贴出来
Python 外部函数调用库ctypes简介
一直对不同语言间的交互感兴趣,python和C语言又深有渊源,所以对python和c语言交互产生了兴趣。
最近了解了python提供的一个外部函数库 ctypes , 它提供了C语言兼容的几种数据类型,并且可以允许调用C编译好的库。
这里是阅读相关资料的一个记录,内容大部分来自 官方文档 。
ctypes 提供了一些原始的C语言兼容的数据类型,参见下表,其中第一列是在ctypes库中定义的变量类型,第二列是C语言定义的变量类型,第三列是Python语言在不使用ctypes时定义的变量类型。
创建简单的ctypes类型如下:
使用 .value 访问和改变值:
改变指针类型的变量值:
如果需要直接操作内存地址的数据类型:
下面的例子演示了使用C的数组和结构体:
创建指针实例
使用cast()类型转换
类似于C语言定义函数时,会先定义返回类型,然后具体实现再定义,当遇到下面这种情况时,也需要这么干:
可以简单地将"so"和"dll"理解成Linux和windows上动态链接库的指代,这里我们以Linux为例。注意,ctypes提供的接口会在不同系统上有出入,比如为了加载动态链接库, 在Linux上提供的是 cdll , 而在Windows上提供的是 windll 和 oledll 。
ctypes会寻找 _as_paramter_ 属性来用作调用函数的参数传入,这样就可以传入自己定义的类作为参数,示例如下:
用 argtypes 和 restype 来指定调用的函数返回类型。
这里我只是列出了 ctypes 最基础的部分,还有很多细节请参考官方文档。
这两天文章没有写,先是早出晚归出去玩了一整天,然后加班到凌晨3点左右,一天一篇计划划水得严重啊…