我使用SWIG将我写的一些C库链接到Python。我的一个C函数将struct作为参数,其中一个数据字段是一个指针(uint32_t * data)。现在我需要读取Python中的文件并将内容传递给该指针。我是这样做的:
p = struct_t() # create the C struct
p.data = open(fp, 'r').read() # let the pointer point to the buffer
feria_op(p) # call the C routine
但是当我运行它时,它会抱怨类型不匹配。我提前感谢,感谢您的帮助。
答案 0 :(得分:2)
作为示例,让我们使用以下头文件(lib.h):
#include <stdint.h>
struct foo {
const uint32_t *data;
};
void bar(struct foo *f);
和相应的实现(lib.c):
#include "lib.h"
#include <stdio.h>
#include <assert.h>
void bar(struct foo *f) {
assert(f);
assert(f->data);
for (unsigned i = 1; i <= f->data[0]; ++i) {
fprintf(stdout, "%d\n", (int)f->data[i]);
}
}
我编译了这个:
gcc -Wall -Wextra -shared -o lib.so lib.c -std=c99 -g
并在文件(input.dat)中生成一些测试数据:
with open('input.dat', 'wb') as f:
f.write(struct.pack("IIII", 3,1,2,3))
这假定您计划阅读的数据已经在您的文件中以机器端格式存在。
可以使用ctypes和SWIG将input.dat的内容从Python传递到bar
{/ 1}}。
foo.data
这里的主要工作是调用import ctypes
lib = ctypes.CDLL("lib.so")
class foo(ctypes.Structure):
_fields_ = [('data', ctypes.POINTER(ctypes.c_uint32))]
bar = lib.bar
bar.argtypes = [ctypes.POINTER(foo)]
# Call the function with the argument:
arg = foo()
with open('input.dat', 'rb') as f:
arg.data = ctypes.cast(ctypes.create_string_buffer(f.read()), ctypes.POINTER(ctypes.c_uint32))
bar(ctypes.byref(arg))
,其字符串缓冲区是根据我们从文件读入的内容创建的,该文件允许分配发生(正确)。
(我认为调用bar时调用ctypes.byref(arg)也是多余的,因为我们已经为bar设置了argtypes。)
对于SWIG,事情有点不同,而不是最简单的SWIG用法。这是因为我们需要进行低级别的投射。 (通常你会做ctypes.cast
并在Python中构建数组,或者只是使用Python列表。)
这是我用于SWIG等效项的模块接口:
%array_class
%module method2
%{
#include "lib.h"
%}
%ignore foo::data; // #1
%include "lib.h"
%rename("%s") foo::data; // #2
// #3
%{
void foo_data_set(struct foo *f, char const *data) {
f->data = data;
}
const char *foo_data_get(const struct foo *f) {
return NULL; // Hard to make this meaningful
}
%}
%extend foo {
const char *data; // #4
}
- 我们想用可以用作String的东西替换它foo::data
的C代码实现getter和setter。所有的辛勤工作实际上是由SWIG图书馆为我们幕后完成的。foo::data
代替foo::data
。我们用以下方式构建它:
const char *
这让我们可以这样写:
swig -python -Wall method2.i && gcc -Wall -Wextra method2_wrap.c -I/usr/include/python2.7/ -lpython2.7 -shared -o _method2.so ./lib.so
这很简单,完全按照您的希望运作。 (注意:这仅适用于Python 2.7,Python 3解决方案稍微复杂一些,因为from method2 import *
# Call the function with the argument:
arg = foo()
with open('input.dat', 'rb') as f:
arg.data = f.read()
bar(arg)
是字节而不是str)