如何在 swig 中公开 C 结构内的可变大小数组?
我现在正在努力几天,以找到一种解决方案来包装C结构,其中包含SWIG中的多个可变大小的INT阵列(存储为指针)。 假设以下最小示例:
typedef struct {
size_t length;
int *a;
int *b;
} mystruct;
其中a
和b
是int
在c
中分配的数组的指示。两个数组的大小都存储在长度
成员中。 现在,我真正想拥有的是两倍:
- 访问
a
和b
在类型myStruct
的对象中的成员应该是安全的,如果索引不合时宜,则应抛出IE例外。 A
和B
中的数据不得复制到Python列表或元组中,但我想提供__ getItem __
方法。这样做的原因是,实际结构由许多这样的阵列组成,它们变得非常巨大,我不想通过复制它们来浪费任何记忆。
我已经看到了如何通过为每个成员编写包装器类和模板,该示例如何通过固定尺寸的阵列来完成此示例,这些成员在内部存储每个数组的大小/长度,例如: swig Interfacing c Intefacing C crublite c python to python(从C'sequence'struct'struct'struct'struct'struct'struct'struct'struct'struct'结构) and swig/python阵列内部结构。 但是,我假设一旦我将a
和b
纳入一类,以使它们能够使用__ getitem __ __
方法进行扩展,我将访问长度
myStruct
的成员,即a
和b
的“容器”。
我在没有成功的情况下尝试的一件事是编写显式_get
和_SET
方法,
typedef struct {
size_t length;
} mystruct;
%extend mystruct {
int *a;
};
%{
int *mystruct_a_get(mystruct *s) {
return mx->a;
}
int *mystruct_b_get(mystruct *s) {
return mx->b;
}
...
%}
但是在这里,整个数组 a a and b
将在没有最大索引的任何控制的情况下返回...
我的目标语言是Python和Perl 5,所以我想人们可以开始为每种语言编写复杂的打字。我之前已经为其他包装纸做了这件事,并希望我的情况有一个更通用的解决方案,只涉及C ++包装器类别等。
任何帮助或想法都将受到赞赏!
编辑可能的解决方案,
因此,我无法放开它,并提出以下(简化)解决方案,这些解决方案或多或少地结合了我在其他地方已经看到的解决方案。想法是为每个包装数组的数组冗余地存储数组长度:
%{
/* wrapper for variable sized arrays */
typedef struct {
size_t length;
int *data;
} var_array_int;
/* convenience constructor for variable sized array wrapper */
var_array_int *
var_array_int_new(size_t length,
int *data)
{
var_array_int *a = (var_array_int *)malloc(sizeof(var_array_int));
a->length = length;
a->data = data;
return a;
}
/* actual structure I want to wrap */
typedef struct {
size_t length;
int *a;
int *b;
} mystruct;
%}
/* hide all struct members in scripting language */
typedef struct {} var_array_int;
typedef struct {} mystruct;
/* extend variable sized arrays with __len__ and __getitem__ */
%extend var_array_int {
size_t __len__() const {
return $self->length;
}
const int __getitem__(int i) const throw(std::out_of_range) {
if ((i < 0) ||
(i >= $self->length))
throw std::out_of_range("Index out of bounds");
return $self->data[i];
}
};
/* add read-only variable sized array members to container struct */
%extend mystruct {
var_array_int *const a;
var_array_int *const b;
};
/* implement explict _get() methods for the variable sized array members */
%{
var_array_int *
mystruct_a_get(mystruct *s)
{
return var_array_int_new(s->length, s->a);
}
var_array_int *
mystruct_b_get(mystruct *s)
{
return var_array_int_new(s->length, s->b);
}
%}
以上解决方案仅提供对变量大小数组的读取访问,并且不包括任何null
null 检查包装int *
指针。我的实际解决方案当然可以做到这一点,还利用模板来包装不同类型的可变大小数组。但是我避免出于清晰的目的表明这里。
我想知道是否有一种更简单的方法可以做上述方法。此外,到目前为止,该解决方案似乎仅在Python中起作用。为Perl 5实施类似的东西已经让我头疼。
I'm struggling for a few days now to find a solution to wrap a C struct containing multiple variable-sized int arrays (stored as pointers) in swig.
Suppose the following minimal example:
typedef struct {
size_t length;
int *a;
int *b;
} mystruct;
where both a
and b
are pointers to int
arrays allocated somewhere in C
. The size of both arrays is stored in the length
member.
Now, what I would really like to have is two-fold:
- access to
a
andb
members in objects of typemystruct
should be safe, i.e. exceptions should be thrown if index is out-of-bounds. - the data in
a
andb
must not be copied-over into a python list or tuple but I want to provide__getitem__
methods instead. The reason for that is that the actual struct consists of many such arrays and they get really huge and I don't want to waste any memory by duplicating them.
I've seen examples how to accomplish this with fixed-sized arrays by writing wrapper classes and templates for each member that internally store the size/length of each array individually, e.g.: SWIG interfacing C library to Python (Creating 'iterable' Python data type from C 'sequence' struct) and SWIG/python array inside structure.
However, I assume once I would wrap a
and b
into a class to enable them to be extended with __getitem__
methods, I won't have access to the length
member of mystruct
, i.e. the 'container' of a
and b
.
One thing I tried without success was to write explicit _get
and _set
methods
typedef struct {
size_t length;
} mystruct;
%extend mystruct {
int *a;
};
%{
int *mystruct_a_get(mystruct *s) {
return mx->a;
}
int *mystruct_b_get(mystruct *s) {
return mx->b;
}
...
%}
But here, the entire arrays a
and b
would be returned without any control of the maximum index...
My target languages are Python and Perl 5, so I guess one could start writing complicated typemaps for each language. I've done that before for other wrappers and hope there is a more generic solution to my situation that involves only C++ wrapper classes and such.
Any help or idea is appreciated!
Edit for possible solution
So, I couldn't let it go and came up with the following (simplified) solution that more or less combines the solutions I already saw elsewhere. The idea was to redundantly store the array lengths for each of the wrapped arrays:
%{
/* wrapper for variable sized arrays */
typedef struct {
size_t length;
int *data;
} var_array_int;
/* convenience constructor for variable sized array wrapper */
var_array_int *
var_array_int_new(size_t length,
int *data)
{
var_array_int *a = (var_array_int *)malloc(sizeof(var_array_int));
a->length = length;
a->data = data;
return a;
}
/* actual structure I want to wrap */
typedef struct {
size_t length;
int *a;
int *b;
} mystruct;
%}
/* hide all struct members in scripting language */
typedef struct {} var_array_int;
typedef struct {} mystruct;
/* extend variable sized arrays with __len__ and __getitem__ */
%extend var_array_int {
size_t __len__() const {
return $self->length;
}
const int __getitem__(int i) const throw(std::out_of_range) {
if ((i < 0) ||
(i >= $self->length))
throw std::out_of_range("Index out of bounds");
return $self->data[i];
}
};
/* add read-only variable sized array members to container struct */
%extend mystruct {
var_array_int *const a;
var_array_int *const b;
};
/* implement explict _get() methods for the variable sized array members */
%{
var_array_int *
mystruct_a_get(mystruct *s)
{
return var_array_int_new(s->length, s->a);
}
var_array_int *
mystruct_b_get(mystruct *s)
{
return var_array_int_new(s->length, s->b);
}
%}
The above solution only provides read access to the variable sized arrays and does not include any NULL
checks for the wrapped int *
pointers. My actual solution of course does that and also makes use of templates to wrap variable sized arrays of different types. But I refrained from showing that here for the sake of clarity.
I wonder if there is an easier way to do the above. Also the solution only seems to work in Python so far. Implementing something similar for Perl 5 already gives me a headache.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论