使用python中的numpy数组分配一个给定大小为16 * 100的缓冲区,并在C中将该缓冲区填充一些结构内容,然后想再次读回python中的该缓冲区。
我有一个结构定义如下:
#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: %d\n", 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: %d\n", p->a);
}
void printLib() {
printf("Oh Yeah.. you are here");
}
void foo(void *p) {
struct desc_data *ptr = (struct desc_data*)p;
printf("id: %d\n", 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 : %d\n", pp->a);
}
用于生成.so文件的命令: gcc -o sample.so -shared -fPIC sample.c
下面是python world的代码:
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。
在此先感谢您,此代码非常糟糕。 :(
答案 0 :(得分:1)
以下代码对我有用:
#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: %d\n", 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: %d\n", p->a);
}
void printLib()
{
printf("Oh Yeah.. you are here");
}
void foo(void *p)
{
struct desc_data *ptr = (struct desc_data*)p;
printf("id: %d\n", 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 : %d\n", pp->a);
}
还有python代码:
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)
答案 1 :(得分:1)
这里是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))