簡體   English   中英

使用Ctypes在C中寫入在python中分配的C緩沖區,然后在python中再次讀回

[英]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的代碼:

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。

在此先感謝您,這個簡單的代碼非常困難。 :(

以下代碼對我有用:

#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM