Featured image of post 关于python调用动态库获取字符串这件事

关于python调用动态库获取字符串这件事

问题的提出

假设我们的动态库代码如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char* new_str(){
    char* str = (char*)malloc(10*sizeof(char));
    strcpy(str, "Hello");
    printf("str: %p\n", str);
    return str;
}

使用如下命令编译

1
gcc -fPIC -shared -o libtest.so test.c

我们可以很轻松的写出(有一点危险)的调用方法

1
2
3
4
from ctypes import *
lib = CDLL("./libtest.so")
lib.new_str.restype = c_char_p 
data = lib.new_str()

我们十分顺利的获得了字符串!但是注意到,我们的字符串是分配在堆上的,这个字符串是什么时候被释放掉的呢? 我做了一个小实验,在一个死循环里不断的获取字符串,不一会儿这个小小的python程序的内存占用就到达了100%,看上去这些内存并没有释放。于是我们编写一个对应的释放函数

1
2
3
void free_str(char* str){
    free(str);
}

在我试图把指针传回给动态库的时候,我注意到data的类型是bytes,也就是说如果你就这么调用如下代码的话

1
lib.free_str(data)

是会报错的。事实上,哪怕你不指定函数的返回类型,或者指定返回类型为c_void_p,你都无法把这个指针传给动态库。 ctypes在调用动态库的时候,默认会把动态库方法的返回类型设置为int如果你把这个整形打印出来和动态库那边的指针作比较,你会发现这两个的值完全不同。

解决方法

把动态库的放回类型设置为POINTER(c_char)即可,代码如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from ctypes import *
 
lib = CDLL("./libtest.so")
lib.new_str.restype = POINTER(c_char) 

while(1):
    p = lib.new_str() 
    data = cast(p, c_char_p).value
    lib.free_str(p)
    print(data)

运行后发现内存占用没有增长,说明内存被成功释放。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计