再谈通过ctypes向C函数传指针

2020年12月2日 / 170次阅读 / Last Modified 2020年12月7日
ctypes

上一篇ctypes的文档(详解ctypes模块及如何调用C函数),其实写的够长了,不过还是有一些重要细节感觉意犹未尽,需要补充。

上篇谈传递指针,基本都是用byref函数来举例,包括传递结构体指针,也是采用先创建一个继承自Structure的对象,然后byref这个对象,再传给C函数。其实,还有更简便的更清晰的方法。

用bytes string

直接在函数接口使用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

用 c_char_p 对象

继续借用上面的例子看代码:

>>> a = c_char_p(b'abcde 12345 kkkkk')
>>> cc.print_str(a)
abcde 12345 kkkkk
18

用struct.pack封装结构体指针

再准备一个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

留言区

您的电子邮箱地址不会被公开。 必填项已用*标注


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top