gpt4 book ai didi

Python ctype - 如何在 C 函数之间传递数据

转载 作者:太空宇宙 更新时间:2023-11-03 11:06:40 28 4
gpt4 key购买 nike

我有一个自制的 C 库,我想使用 python 访问它。问题在于代码主要由两部分组成,一个是从多个文件中读取数据的初始化,另一个是一些只需执行一次的计算。另一部分循环调用,重复使用之前生成的数据。对于这个函数,我想从 python 传递参数。

我的想法是编写两个 C 包装函数,“init”和“loop”——“init”读取数据并返回一个指向结构的空指针,“loop”可以与我可以传递的附加参数一起使用来自 python 。有点像

void *init() {
struct *mystruct ret = (mystruct *)malloc(sizeof(mystruct));
/* Fill ret with data */
return ret;
}

float loop(void *data, float par1, float par2) {
/* do stuff with data, par1, par2, return result */
}

我尝试从 python 中调用“init”作为 c_void_p,但是由于“loop”改变了“data”的一些内容并且 ctypes 的 void 指针是不可变的,所以这没有用。

我看到的类似问题的其他解决方案似乎需要知道“init”会使用多少内存,但我不知道。

有没有一种方法可以通过 python 将数据从一个 C 函数传递到另一个函数,而无需告诉 python 确切的数据是什么或多少?或者有其他方法可以解决我的问题吗?


我尝试(但失败了)编写一个最小崩溃示例,经过一些调试后发现我的 C 代码中存在错误。感谢所有回复的人!希望这可能对其他人有所帮助,这是一个最小的工作版本(仍然没有单独的“免费” - 抱歉):

pybug.c:

#include <stdio.h>
#include <stdlib.h>

typedef struct inner_struct_s {
int length;
float *array;
} inner_struct_t;

typedef struct mystruct_S {
int id;
float start;
float end;
inner_struct_t *inner;
} mystruct_t;

void init(void **data) {
int i;
mystruct_t *mystruct = (mystruct_t *)malloc(sizeof(mystruct_t));
inner_struct_t *inner = (inner_struct_t *)malloc(sizeof(inner_struct_t));
inner->length = 10;
inner->array = calloc(inner->length, sizeof(float));
for (i=0; i<inner->length; i++)
inner->array[i] = 2*i;
mystruct->id = 0;
mystruct->start = 0;
mystruct->end = inner->length;
mystruct->inner = inner;
*data = mystruct;
}

float loop(void *data, float par1, float par2, int newsize) {
mystruct_t *str = data;
inner_struct_t *inner = str->inner;
int i;
inner->length = newsize;
inner->array = realloc(inner->array, newsize * sizeof(float));
for (i=0; i<inner->length; i++)
inner->array[i] = par1 + i * par2;
return inner->array[inner->length-1];
}

编译为

cc -c -fPIC pybug.c
cc -shared -o libbug.so pybug.o

在 python 中运行:

from ctypes import *
sl = CDLL('libbug.so')
# What arguments do functions take / return?
sl.init.argtype = c_void_p
sl.loop.restype = c_float
sl.loop.argtypes = [c_void_p, c_float, c_float, c_int]

# Init takes a pointer to a pointer
px = c_void_p()
sl.init(byref(px))

# Call the loop a couple of times
for i in range(10):
print sl.loop(px, i, 5, 10*i+5)

最佳答案

当调用者完成时,您应该有一个相应的函数来释放数据缓冲区。否则我看不到这个问题。只需将指针传递给从 init 获得的 loop

init.restype = c_void_p
loop.argtypes = [c_void_p, c_float, c_float]
loop.restype = c_float

我不确定你所说的“ctypes 的空指针是不可变的”是什么意思,除非你在谈论 c_char_pc_wchar_p。问题在于,如果您将 Python 字符串作为参数传递,它会使用 Python 指向字符串缓冲区的私有(private)指针。如果函数可以更改字符串,您应该首先将其复制到 c_charc_wchar 数组。

这是一个简单的示例,展示了将 Python 字符串(2.x 字节字符串)作为参数传递给修改它的函数的问题。在这种情况下,它将索引 0 更改为 '\x00':

>>> import os
>>> from ctypes import *
>>> open('tmp.c', 'w').write("void f(char *s) {s[0] = 0;}")
>>> os.system('gcc -shared -fPIC -o tmp.so tmp.c')
0
>>> tmp = CDLL('./tmp.so')
>>> tmp.f.argtypes = [c_void_p]
>>> tmp.f.restype = None
>>> tmp.f('a')
>>> 'a'
'\x00'
>>> s = 'abc'
>>> tmp.f(s)
>>> s
'\x00bc'

这是特定于将 Python 字符串作为参数传递的。将指针传递给旨在可变的数据结构不是问题,可以是 ctypes 数据对象,例如 Structure,也可以是库返回的指针。

关于Python ctype - 如何在 C 函数之间传递数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17493310/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com