用 C 格式写入缓冲区,该缓冲区使用 ctypes 在 python 中分配,并在 python 中再次读回



问题陈述:

在 python 中使用 numpy 数组分配一个给定大小为 16*100 的缓冲区,并在 C 中用一些结构内容填充该缓冲区,然后想在 python 中再次读回该缓冲区。

我有一个结构定义如下:

样本.c

#include <stdio.h>
typedef unsigned char           uint8_t;
typedef short                   int16_t;
typedef unsigned short          uint16_t;
struct S{
int a;
};
struct ins_data {
int16_t offset1;
int16_t num1;
int16_t offset2;
int16_t num2;
void *buffer;  //==> Need to fill this buffer with struct S contents
};
struct desc_data {
uint8_t id;
void *ins_data;
};
void access_ins_data(struct ins_data* ptr) {
int i = 0;
struct S *p = (struct S*)ptr->buffer;
printf("offset1: %dn", ptr->offset1);
ptr->offset1 = 12;
ptr->num1 = 13;
struct S tt;
tt.a = 10;
memcpy(p, &tt, sizeof(struct S));
/* Want to fill this buffer in below fashion, but its not even working for single case.
* |struct S s1|struct S s2| struct S s3|
*
*/
printf("S.a: %dn", p->a);
}
void printLib() {
printf("Oh Yeah.. you are here");
}
void foo(void *p) {
struct desc_data *ptr = (struct desc_data*)p;
printf("id: %dn", ptr->id);
access_ins_data(ptr->ins_data);
struct ins_data *ss = (struct ins_data *)ptr->ins_data;
struct S *pp = (struct S*)ss->buffer;
printf("foo : %dn", pp->a);
}

用于生成 .so 文件的命令:gcc -o sample.so -shared -fPIC sample.c

下面是python世界的代码:

samplePython.py

from ctypes import *
import numpy as np
class S(Structure):
pass
S._fields_ = [
('a', c_int32),
]
class ins_data(Structure):
pass
int16_t = c_int16
ins_data._fields_ = [
('offset1', int16_t),
('num1', int16_t),
('offset2', int16_t),
('num2', int16_t),
('buffer', c_void_p),
]
class desc_data(Structure):
pass
uint8_t = c_uint8
desc_data._fields_ = [
('id', uint8_t),
('ins_data', c_void_p),
]
def get_ins_data():
arr = np.zeros(16*100, dtype='uint8')
enc_data = ins_data(-1,0,-1,0)
enc_data.buffer = cast(np.ctypeslib.as_ctypes(arr), c_void_p)
return enc_data
from ctypes import cdll
newA = cdll.LoadLibrary("sample.so")
foo = newA.foo
foo.argtypes = [c_void_p]
foo.restype = None
insData = get_ins_data()
descData = desc_data(0, cast(byref(insData), c_void_p))
foo(cast(byref(descData), c_void_p))
print "descData.id", descData.id
tt= cast(descData.ins_data, POINTER(ins_data))
buff = cast(tt[0].buffer, POINTER(S))
print "buffer content", buff.contents.a

输出:

id: 0
offset1: -1
S.a: 10
foo : 10
descData.id:  0
buffer content 1140653488 #This should come 10?

问题:

显示垃圾值的缓冲区内容。它应该显示 10。

提前感谢,严重卡在这个简单的代码中。 :(

这里转换 C 代码(主函数(:

from ctypes import *
import numpy as np
class S(Structure):
_fields_ = [
('a', c_int32)
]
class ins_data(Structure):
_fields_ = [
('offset1', c_int16),
('num1', c_int16),
('offset2', c_int16),
('num2', c_int16),
('buffer', c_void_p)
]
class desc_data(Structure):
_fields_ = [
('id', c_uint8),
('ins_data', c_void_p)
]

from ctypes import cdll
newA = cdll.LoadLibrary("./sample.so")
foo = newA.foo
foo.argtypes = [c_void_p]
foo.restype = None

A = create_string_buffer(16 * 100)
dData = desc_data()
iData = ins_data()
dData.id = 1
iData.offset1 = -1
iData.num1 = 0
iData.offset2 = -1
iData.num2 = 0
iData.buffer = cast(A, c_void_p)
dData.ins_data = cast(pointer(iData), c_void_p)
foo(byref(dData))
pp = cast(dData.ins_data, POINTER(ins_data))
p = cast(pp.contents.buffer, POINTER(S))
print("@@@@: {}".format(p[0].a))
print("@@@@: {}".format(p[1].a))
print("@@@@: {}".format(p[2].a))

以下代码对我有用:

#include <stdio.h>
#include <stdint.h>
#include <string.h>
struct S {
int32_t a;
};
struct ins_data {
int16_t offset1;
int16_t num1;
int16_t offset2;
int16_t num2;
void *buffer;  //==> Need to fill this buffer with struct S contents
};
struct desc_data {
uint8_t id;
void *ins_data;
};
void access_ins_data(struct ins_data* ptr)
{
struct S *p = (struct S*)ptr->buffer;
printf("offset1: %dn", ptr->offset1);
ptr->offset1 = 12;
ptr->num1 = 13;
struct S tt;
tt.a = 10;
memcpy(p, &tt, sizeof(struct S));
/* Want to fill this buffer in below fashion, but its not even working for single case.
* |struct S s1|struct S s2| struct S s3|
*
*/
printf("S.a: %dn", p->a);
}
void printLib()
{
printf("Oh Yeah.. you are here");
}
void foo(void *p)
{
struct desc_data *ptr = (struct desc_data*)p;
printf("id: %dn", ptr->id);
access_ins_data(ptr->ins_data);
struct ins_data *ss = (struct ins_data *)ptr->ins_data;
struct S *pp = (struct S*)ss->buffer;
printf("foo : %dn", pp->a);
}

而蟒蛇代码:

from ctypes import *
import numpy as np
class S(Structure):
_fields_ = [
('a', c_int32)
]
class ins_data(Structure):
_fields_ = [
('offset1', c_int16),
('num1', c_int16),
('offset2', c_int16),
('num2', c_int16),
('buffer', c_void_p)
]
class desc_data(Structure):
_fields_ = [
('id', c_uint8),
('ins_data', c_void_p)
]
def get_ins_data():
arr = create_string_buffer(16 * 100)
#arr = np.zeros(16*100, dtype='uint8')
insData = ins_data(-1, 0, -1, 0, 0)
insData.buffer = cast(arr, c_void_p)
#insData.buffer = cast(np.ctypeslib.as_ctypes(arr), c_void_p)
return insData
from ctypes import cdll
newA = cdll.LoadLibrary("./sample.so")
foo = newA.foo
foo.argtypes = [c_void_p]
foo.restype = None
insData = get_ins_data()
descData = desc_data(0, cast(pointer(insData), c_void_p))
foo(byref(descData))
print("descData.id", descData.id)
tt = cast(descData.ins_data, POINTER(ins_data))
buff = cast(tt[0].buffer, POINTER(S))
print("buffer content", buff.contents.a)

不应使用byref,而应在需要创建真指针时使用pointer

为了使用 Numpy,我们需要保留对局部变量(数组(的引用。例如,此代码不会发生段错误:

from ctypes import *
import numpy as np
class S(Structure):
_fields_ = [
('a', c_int32)
]
class ins_data(Structure):
_fields_ = [
('offset1', c_int16),
('num1', c_int16),
('offset2', c_int16),
('num2', c_int16),
('buffer', c_void_p)
]
class desc_data(Structure):
_fields_ = [
('id', c_uint8),
('ins_data', c_void_p)
]

from ctypes import cdll
newA = cdll.LoadLibrary("./sample.so")
foo = newA.foo
foo.argtypes = [c_void_p]
foo.restype = None

arrNp = np.zeros(16*100, dtype='uint8')
arr = np.ctypeslib.as_ctypes(arrNp)
# If the following line is un-commented, the code segfault since python will GC the array referenced by `arr`
#arrNp = None
insData = ins_data(-1, 0, -1, 0, 0)
insData.buffer = cast(arr, c_void_p)
descData = desc_data(0, cast(pointer(insData), c_void_p))
foo(byref(descData))
print("descData.id", descData.id)
tt = cast(descData.ins_data, POINTER(ins_data))
print hex(descData.ins_data)
print hex(tt.contents.buffer)
buff = cast(tt[0].buffer, POINTER(S))
print("buffer content", buff.contents.a)

最新更新