Python进阶篇-ctypes(上)

在Windows平台上,把一些常用的算法或者功能封装成库是非常常见的,在开发python程序的时候,我们可能会用到这功能,把C/C++代码转化为python代码可能是一个非常出力不讨好的事情,这时候python调用C就会体现出巨大的优势(不过多考虑运行效率的情况下)。Python调C的核心就在于数据类型的转换,这里和大家一起探讨一下ctypes的用法。
https://docs.python.org/zh-cn/3.7/library/ctypes.html
作为准备请读一读官方的文档。
对于简单的数据类型,这里就不过多介绍了,请参考官方文档。
接下来,我们重点看一下复杂的数据结构:结构体。
首先,我们来编写一个Windows平台下的动态库。

typedef struct _Coordinate {
	int x;
	int y;
}Coordinate, * PCoordinate;

int add(Coordinate pt)
{
	int result = 0;
	result = pt.x + pt.y;
	return result;
}

接下来我们,来编写python代码来调用dll,代码如下:

import ctypes
from ctypes import *


class Coordinate(Structure):
    _fields_ = [
        ('x', ctypes.c_int),
        ('y', ctypes.c_int)
    ]


def main():
    coord = Coordinate(2, 3)
    mydll = ctypes.WinDLL("path/to/dll")
    result = mydll.add(coord)
    print(result)


if __name__ == "__main__":
    main()

这个例子应该很好懂,接下来升级一下这个问题,结构体嵌套
修改我们的dll 库,代码如下

typedef struct _Coordinate {
	int x;
	int y;
}Coordinate, * PCoordinate;


typedef struct _Point {
	Coordinate coordinate;
}Point, *PPoint;


int add(Point pt)
{
	int result = 0;
	result = pt.coordinate.x + pt.coordinate.y;
	return result;
}

修改python 代码如下:

import ctypes
from ctypes import *


class Coordinate(Structure):
    _fields_ = [
        ('x', ctypes.c_int),
        ('y', ctypes.c_int)
    ]


class Point(Structure):
    _fields_ = [
        ('coordinate', Coordinate)
    ]

def main():
    coord = Coordinate(2, 3)
    pt = Point(coord)
    mydll = ctypes.WinDLL("path/to/dll")
    result = mydll.add(pt)
    print(result)


if __name__ == "__main__":
    main()

进一步升级这个问题,传结构体指针给dll
修改dll 代码如下:

typedef struct _Coordinate {
	int x;
	int y;
}Coordinate, * PCoordinate;


typedef struct _Point {
	Coordinate coordinate;
}Point, *PPoint;


int add(PPoint pt)
{
	int result = 0;
	result = pt->coordinate.x + pt->coordinate.y;
	return result;
}

修改python代码如下:

import ctypes
from ctypes import *


class Coordinate(Structure):
    _fields_ = [
        ('x', ctypes.c_int),
        ('y', ctypes.c_int)
    ]


class Point(Structure):
    _fields_ = [
        ('coordinate', Coordinate)
    ]

def main():
    coord = Coordinate(2, 3)
    pt = Point(coord)
    mydll = ctypes.WinDLL("D:\\Code\\C\\Test\\Test\\x64\\Debug\\Test.dll")
    result = mydll.add(ctypes.byref(pt))
    print(result)


if __name__ == "__main__":
    main()

让我们来进一步升级这个问题, 在结构体内定义,指针变量。
修改dll代码如下:

typedef struct _Coordinate {
	int x;
	int y;
}Coordinate, * PCoordinate;


typedef struct _Point {
	PCoordinate coordinate;
}Point, *PPoint;


int add(PPoint pt)
{
	int result = 0;
	result = pt->coordinate->x + pt->coordinate->y;
	return result;
}

修改python代码如下:

import ctypes
from ctypes import *


class Coordinate(Structure):
    _fields_ = [
        ('x', ctypes.c_int),
        ('y', ctypes.c_int)
    ]


class Point(Structure):
    _fields_ = [
        ('coordinate', POINTER(Coordinate))
    ]


def main():
    coord = Coordinate(2, 3)
    pt = Point(pointer(coord))

    mydll = ctypes.WinDLL("D:\\Code\\C\\Test\\Test\\x64\\Debug\\Test.dll")
    res = mydll.add(ctypes.byref(pt))
    print(res)


if __name__ == "__main__":
    main()

最后我们再来聊一下,POINTER, byref和pointer三者的区别。
POINTER:接受ctypes类型返回新的类型,类似 T*
pointer:返回的是一个具体的实例对象
关于byref官方的解释如下:
“ctypes exports the byref() function which is used to pass parameters by reference. The same effect can be achieved with the pointer() function, although pointer() does a lot more work since it constructs a real pointer object, so it is faster to use byref() if you don’t need the pointer object in Python itself:”
大概就是pointer会返回对象而byref不会,所以byref更快,另外byref只在传参的时候使用。

接下来还有数组,字节序,以及位域相关的东西,下一篇来写。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值