本文介绍了Python Ctypes 0大小的数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在很多地方找到了这个,并尝试使用cast,但是没有成功。

I have look on many places for this, and have tried using cast, but had no success.

我在c中有一个结构,例如:

I have a struct in c like:

struct t{
int x;
struct y[0];
};

我如何调整结构y的大小?我在SO上尝试了此问题的其他类型(),但不断出现此错误。

How would I resize the array of struct y? I tried the other types of this issue on SO (does python ctypes supports size-0 array?), but kept on getting this error.

TypeError: incompatible types, y_Array_20 instance instead of y_Array_0 instance


推荐答案

我引用的其他答案只是一个返回大小结构的示例,并且正如该答案中的注释所表明的那样,使用大小合适的数组可以防止意外读取超出数组末尾的内容。下面的示例显示了一种确定数组大小的方法,无论DLL函数返回一个还是用户创建一个并将其传递。

My other answer you reference just has an example of returning a sized structure, and as the comments in that answer indicate, using a sized array time prevents accidently reading past the end of the array. This example below shows a way to size the array whether the DLL function returns one or the user creates one and passes it in.

test.c:

#include <stdlib.h>

#define API __declspec(dllexport)

typedef struct Test {
    int size;
    int arr[0];
} Test;

API int Test_use(Test* test) {
    int sum = 0;
    for(int i = 0; i < test->size; ++i)
        sum += test->arr[i];
    return sum;
}

API struct Test* Test_alloc(int size) {
    struct Test* t = malloc(sizeof(struct Test) + size * sizeof(int));
    if(t != NULL) {
        t->size = size;
        for(int i = 0; i < size; ++i)
            t->arr[i] = i;
    }
    return t;
}

API void Test_free(struct Test* test) {
    free(test);
}

test.py:

from ctypes import *

class Test:
    # return a customized Test instance of the correct array size
    def __new__(cls,size,*init):
        if len(init) > size:
            raise ValueError('too many initializers')
        # "type" creates new types.
        # type(name_of_type,bases,dict_of_attributes)
        # It is instantiated with the size and initial array values.
        return type(f'Test{size}', (Structure,), {
            '_fields_': [('size',c_int),
                         ('arr',c_int * size)]})(size,(c_int * size)(*init))

# This is the pointer type the functions need.
# In this case Test(0) returns a Test0 instance.
# "type" is used to get the type the pointer references.
PTEST = POINTER(type(Test(0)))

dll = CDLL('./test')

dll.Test_use.argtypes = PTEST,
dll.Test_use.restype = c_int
def Test_alloc(n):
    # The DLL function returns the generate Test0 type,
    # so this helper casts it to the TestN pointer type.
    t = dll.Test_alloc(n)
    return cast(t,POINTER(type(Test(t.contents.size))))

dll.Test_alloc.argtypes = c_int,
dll.Test_alloc.restype = PTEST
def Test_use(t):
    # The DLL function needs the Test0 pointer type,
    # so this helper casts it.
    return dll.Test_use(cast(t,PTEST))

dll.Test_free.argtypes = PTEST,
dll.Test_free.restype = None
def Test_free(t):
    # The DLL function needs the Test0 pointer type,
    # so this helper casts it.
    dll.Test_free(cast(t,PTEST))

t = Test_alloc(5)
print(type(t),t.contents.size,list(t.contents.arr))
print(Test_use(t))
Test_free(t)

n = Test(7,1,2,3)
print(type(n),n.size,list(n.arr))
print(Test_use(byref(n)))

输出:

<class '__main__.LP_Test5'> 5 [0, 1, 2, 3, 4]
10
<class '__main__.Test7'> 7 [1, 2, 3, 0, 0, 0, 0]
6

这篇关于Python Ctypes 0大小的数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 05:53