[英]Write buffer in C which is allocated in python using ctypes, and read back again in python
使用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。
在此先感謝您,這個簡單的代碼非常困難。 :(
以下代碼對我有用:
#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)
這里是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))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.