ctypes是python的一个函数库,提供和C语言兼容的数据类型,可以直接调用动态链接库中的导出函数。

为了使用ctypes,必须依次完成以下步骤:

·加载动态链接库

·将python对象转换成ctypes所能识别的参数

·使用ctypes所能识别的参数调用动态链接库中的函数

动态链接库加载方式有三种:

·cdll

·windll

·oledll

它们的不同之处在于:动态链接库中的函数所遵守的函数调用方式(calling convention)以及返回方式有所不同。

cdll用于加载遵循cdecl调用约定的动态链接库,windll用于加载遵循stdcall调用约定的动态链接库,oledll与windll完全相同,只是会默认其载入的函数统一返回一个Windows HRESULT错误编码。函数调用约定:函数调用约定指的是函数参数入栈的顺序、哪些参数入栈、哪些通过寄存器传值、函数返回时栈帧的回收方式

(是由调用者负责清理,还是被调用者清理)、函数名称的修饰方法等等。常见的调用约定有cdecl和stdcall两种。

在《程序员的自我修养--链接、装载与库》一书的第10章有对函数调用约定的更详细介绍。

cdecl规定函数参数列表以从右到左的方式入栈,且由函数的调用者负责清除栈帧上的参数。stdcall的参数入栈方式与cdecl一致,

但函数返回时是由被调用者自己负责清理栈帧。而且stdcall是Win32 API函数所使用的调用约定。

例子:

Linux下:

或者:

其他例子:

相关推荐:《Python基础教程》

一个完整的例子:

1.编写动态链接库// filename: foo.c

#include "stdio.h"

char* myprint(char *str)

{

puts(str);

return str;

}

float add(float a, float b)

{

return a + b;

}

将foo.c编译为动态链接库:gcc -fPIC -shared foo.c -o foo.so

2.使用ctypes调用foo.so#coding:utf8

#FILENAME:foo.py

from ctypes import *

foo = CDLL('./foo.so')

myprint = foo.myprint

myprint.argtypes = [POINTER(c_char)] # 参数类型为char指针

myprint.restype = c_char_p # 返回类型为char指针

res = myprint('hello ctypes')

print(res)

add = foo.add

add.argtypes = [c_float, c_float] # 参数类型为两个float

add.restype = c_float # 返回类型为float

print(add(1.3, 1.2))

执行:[jingjiang@iZ255w0dc5eZ test]$ python2.6 foo.py

hello ctypes

hello ctypes

2.5

ctypes数据类型和C数据类型对照表

查找动态链接库>>> from ctypes.util import find_library

>>> find_library("m")

'libm.so.6'

>>> find_library("c")

'libc.so.6'

>>> find_library("bz2")

'libbz2.so.1.0'

函数返回类型

函数默认返回 C int 类型,如果需要返回其他类型,需要设置函数的 restype 属性。>>> from ctypes import *

>>> from ctypes.util import find_library

>>> libc = cdll.LoadLibrary(find_library("c"))

>>> strchr = libc.strchr

>>> strchr("abcdef", ord("d"))

-808023673

>>> strchr.restype = c_char_p

>>> strchr("abcdef", ord("d"))

'def'

>>> strchr("abcdef", ord("x"))

回调函数

·定义回调函数类型,类似于c中的函数指针,比如:void (*callback)(void* arg1, void* arg2),定义为:callack = CFUNCTYPE(None, cvoidp, cvoidp)

None表示返回值是void,也可以是其他类型。剩余的两个参数与c中的回调参数一致。

·定义python回调函数:def _callback(arg1, arg2):

#do sth

# ...

#return sth

·注册回调函数:cb = callback(_callback)

另外,使用ctypes可以避免GIL的问题。

一个例子://callback.c

#include "stdio.h"

void showNumber(int n, void (*print)())

{

(*print)(n);

}

编译成动态链接库:gcc -fPIC -shared -o callback.so callback.c

编写测试代码:#FILENAME:callback.py

from ctypes import *

_cb = CFUNCTYPE(None, c_int)

def pr(n):

print 'this is : %d' % n

cb = _cb(pr)

callback = CDLL("./callback.so")

showNumber = callback.showNumber

showNumber.argtypes = [c_int, c_void_p]

showNumber.restype = c_void_p

for i in range(10):

showNumber(i, cb)

执行:$ python2.7 callback.py

this is : 0

this is : 1

this is : 2

this is : 3

this is : 4

this is : 5

this is : 6

this is : 7

this is : 8

this is : 9

结构体和联合union(联合体 共用体)

1、union中可以定义多个成员,union的大小由最大的成员的大小决定。

2、union成员共享同一块大小的内存,一次只能使用其中的一个成员。

3、对某一个成员赋值,会覆盖其他成员的值(也不奇怪,因为他们共享一块内存。但前提是成员所占字节数相同,

当成员所占字节数不同时只会覆盖相应字节上的值,>比如对char成员赋值就不会把整个int成员覆盖掉,因为char只占一个字节,

而int占四个字节)

4、联合体union的存放顺序是所有成员都从低地址开始存放的。

结构体和联合必须从Structure和Union继承,子类必须定义__fields__属性,__fields__属性必须是一个二元组的列表,包含field的名称和field的类型,field类型必须是一个ctypes的类型,例如:c_int, 或者其他继承自ctypes的类型,例如:结构体,联合,数组,指针。from ctypes import *

class Point(Structure):

__fields__ = [         ("x", c_int),

("y", c_int),

]

def __str__(self):

return "x={0.x}, y={0.y}".format(self)

point1 = Point(x=10, y=20)

print "point1:", point1

class Rect(Structure):

__fields__ = [

("upperleft", Point),

("lowerright", Point),

]

def __str__(self):

return "upperleft:[{0.upperleft}], lowerright:[{0.lowerright}]".format(self)

rect1 = Rect(upperleft=Point(x=1, y=2), lowerright=Point(x=3, y=4))

print "rect1:", rect1

运行:python test.py

point1: x=10, y=20

rect1: upperleft:[x=1, y=2], lowerright:[x=3, y=4]

数组

数组定义很简单,比如:定义一个有10个Point元素的数组,

TenPointsArrayType = Point * 10。

初始化和使用数组:from ctypes import *

TenIntegersArrayType = c_int * 10

array1 = TenIntegersArrayType(*range(1, 11))print array1

for i in array1:

print i

运行:$ python2.7 array.py

1

2

3

4

5

6

7

8

9

10

指针

pointer()可以创建一个指针,Pointer实例有一个contents属性,返回指针指向的内容。>>> from ctypes import *

>>> i = c_int(42)

>>> p = pointer(i)

>>> p<__main__.lp_c_int>

>>> p.contents

c_int(42)

>>>

可以改变指针指向的内容>>> i = c_int(99)

>>> p.contents = i

>>> p.contents

c_int(99)

可以按数组的方式访问,并改变值>>> p[0]

99

>>> p[0] = 22

>>> i

c_int(22)

传递指针或引用

很多情况下,c函数需要传递指针或引用,ctypes也完美支持这一点。

byref()用来传递引用参数,pointer()也可以完成同样的工作,但是pointer会创建一个实际的指针对象,如果你不需要一个指针对象,用byref()会快很多。>>> from ctypes import *

>>> i = c_int()

>>> f = c_float()

>>> s = create_string_buffer('

python ctypes教程_python ctypes是什么相关推荐

  1. python ctypes教程_Python ctypes: Python file object - C FILE * | 易学教程

    可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试): 问题: I am using ctypes to wrap a C-library (which I ...

  2. 视频教程-快速入门Python基础教程_Python基础知识大全-Python

    快速入门Python基础教程_Python基础知识大全 十余年计算机技术领域从业经验,在中国电信.盛大游戏等多家五百强企业任职技术开发指导顾问,国内IT技术发展奠基人之一. 杨千锋 ¥99.00 立即 ...

  3. 视频教程-快速入门Python基础教程_Python基础进阶视频-Python

    快速入门Python基础教程_Python基础进阶视频 十余年计算机技术领域从业经验,在中国电信.盛大游戏等多家五百强企业任职技术开发指导顾问,国内IT技术发展奠基人之一. 杨千锋 ¥199.00 立 ...

  4. python ctypes 指针_Python Ctypes传递.h文件中定义的结构指针。

    我认为您可能缺少的是确切地知道您希望分配结构内存的位置.下面的c代码提供了一个为struct分配内存并返回指向它的指针的函数(new_struct()).#include #include #incl ...

  5. python教程是什么-Python基础教程_Python入门知识

    Python基础教程频道为编程初学者提供入门前的所有基础知识,必须要掌握的一些PYTHON基础语法语句,基本的数据类型. 让大家可以更快速.更容易理解的的方式掌握Python编程所需要的基础知识,灵活 ...

  6. python 3教程_Python 3 教程

    全屏 Python 3 教程 Python的3.0版本,常被称为Python 3000,或简称Py3k.相对于Python的早期版本,这是一个较大的升级.为了不带入过多的累赘,Python 3.0在设 ...

  7. python基础教程是什么-Python基础教程_Python入门知识

    Python基础教程频道为编程初学者提供入门前的所有基础知识,必须要掌握的一些PYTHON基础语法语句,基本的数据类型. 让大家可以更快速.更容易理解的的方式掌握Python编程所需要的基础知识,灵活 ...

  8. python后端教程_Python学习教程(技术干货):关于前后端分离开发入门

    原标题:Python学习教程(技术干货):关于前后端分离开发入门 对于程序员来说,其实Tab和空格远远不只是"立场"问题那么简单. 在不同的编辑器里tab的长度可能不一致,所以在一 ...

  9. python itchat教程_Python学习教程:教你用Python通过微信来控制电脑摄像头

    原标题:Python学习教程:教你用Python通过微信来控制电脑摄像头 如果说强大的标准库奠定了Python发展的基石,丰富的第三方库则是python不断发展的保证.今天的Python学习教程就来通 ...

最新文章

  1. Linux 引导和系统启动
  2. Reporting Service 告警w WARN: Thread pool pressure. Using current thread for a work item
  3. 如果不能调试存储过程
  4. 天翼云从业认证(3.6)了解天翼云大数据SaaS服务
  5. 页面显示其他php,php – 分页在所有其他页面上显示来自第1页的相同帖子
  6. 2017-06-23
  7. mysql按行取数据_菜鸟求助:怎么在mysql隔12行取一条数据呀??
  8. 关于 CSS will-change 属性你需要知道的事
  9. 使用Ant定义生成文件
  10. jquery ajax请求方式与提示用户正在处理请稍等,等待数据返回时loading的显示
  11. 收藏 | 数据资源下载网址大全
  12. RequestDispatcher请求转发方法
  13. C++ STL库(6)
  14. java毕业设计物流跟踪系统mybatis+源码+调试部署+系统+数据库+lw
  15. RTKLIB-RTKPOST设置介绍
  16. ★Kali信息收集~ 5.The Harvester:邮箱挖掘器
  17. VBA之正则表达式(33)-- 网页表格提取数据
  18. 荣耀v40轻奢版和华为nova8的区别 哪个好
  19. python-gitlab
  20. 51单片机_7-2 使用内部计时器实现时钟显示

热门文章

  1. 文本自动化摘要方法学习笔记
  2. 等级保护和分级保护区别与联系
  3. 深入理解nvme协议之二:nvme 协议重点数据结构之间的关系
  4. 论文分析与讲解思路(2)--PGCN
  5. 群创15.6寸工业屏G156HCE-E01-15.6寸EDP接口
  6. numpy中的插值函数interp
  7. 事实表的分类:事务事实表,周期快照事实表,累计快照事实表
  8. SQL语法——LIKE
  9. rootfs 制作ubuntu_如何构建一个arm64 AArch64的Ubuntu rootfs
  10. Kafka学习笔记-常用命令