2020年12月2日 / 496次阅读 / Last Modified 2020年12月7日
ctypes
上一篇ctypes的文档(详解ctypes模块及如何调用C函数),其实写的够长了,不过还是有一些重要细节感觉意犹未尽,需要补充。
上篇谈传递指针,基本都是用byref函数来举例,包括传递结构体指针,也是采用先创建一个继承自Structure的对象,然后byref这个对象,再传给C函数。其实,还有更简便的更清晰的方法。
直接在函数接口使用Python的bytes string,就是传递字符串指针的效果。
>>> from ctypes import *
>>> libc = CDLL('libc.so.6')
a>>> libc.printf(b"abcde 12345\n")
abcde 12345
12
继续看代码。下面是一段C代码,接收一个char *str指针,然后以字符串的方式从这个地址开始打印:
#include
void print_str(char *str)
{
printf("%s\n",str);
}
在Python中,可以这样来调用(编译成.so这部分就省略了,下同):
>>> from ctypes import *
>>> cc = CDLL('./c2.so')
>>> cc.print_str(b'abcde')
abcde
6
>>> cc.print_str(b'abcde1234567')
abcde1234567
13
继续借用上面的例子看代码:
>>> a = c_char_p(b'abcde 12345 kkkkk')
>>> cc.print_str(a)
abcde 12345 kkkkk
18
再准备一个C函数,接收一个结构体指正,然后打印结构体中各项的内容:
#include
typedef struct {
int a;
int b;
double c;
} abc;
void show_abc(abc *in)
{
printf("%d %d %f\n",in->a,in->b,in->c);
}
下面是Python代码的调用方式(不写ctypes.Structure继承类):
>>> from ctypes import *
>>> cc = CDLL('./c2.so')
>>>
>>> import struct
>>> cc.show_abc(struct.pack('iid',1,2,3))
1 2 3.000000
13
struct.pack返回的就是一个已经格式化后的byte string,'iid'是格式化字符串,对应C代码中的abc结构体,必须要对应哈。
给C函数传递byte string,就是传递指针!
最后补充传递函数指针,其实,就是直接通过ctypes使用函数名。
/* for qsort in libc */
int
cmp_int(const void *keyval, const void *datum)
{
return (*(int*)keyval - *(int*)datum);
}
这个C函数,是给C标准库中的qsort准备的,下面的Python代码,会将这个函数传递给libc.qsort(代码省略了部分内容):
def test_libc_qsort(self):
libc = ctypes.CDLL('libc.so.6')
libc.qsort(self.dca02,
len(self.a02),
ctypes.sizeof(ctypes.c_int),
self.get_sort().cmp_int)
self.assertEqual(list(self.ca02), sorted(self.a02))
libc.qsort(self.dca03,
len(self.a03),
ctypes.sizeof(ctypes.c_int),
self.get_sort().cmp_int)
self.assertEqual(list(self.ca03), sorted(self.a03))
以上单元测试是成功的,具体代码在我个人的common项目中。
-- EOF --
本文链接:https://www.pynote.net/archives/2961
Ctrl+D 收藏本页
©Copyright 麦新杰 Since 2019 Python笔记