SWIG使用简明教程(二)
结构体和联合体
如果SWIG遇到结构或联合的定义,它将创建一组访问器函数。SWIG生成的访问器函数仅获取指向对象的指针,并允许访问单个成员。 例如,声明
struct Vector {
double x, y, z;
}
SWIG会转换为以下访问函数集
double Vector_x_get(struct Vector *obj) { return obj->x; } double Vector_y_get(struct Vector *obj) { return obj->y; } double Vector_z_get(struct Vector *obj) { return obj->z; } void Vector_x_set(struct Vector *obj, double value) { obj->x = value; } void Vector_y_set(struct Vector *obj, double value) { obj->y = value; } void Vector_z_set(struct Vector *obj, double value) { obj->z = value; }
如果在接口中未定义默认的构造函数和析构函数,SWIG将创建默认构造函数和析构函数
struct Vector *new_Vector() { return (Vector *) calloc(1, sizeof(struct Vector)); } void delete_Vector(struct Vector *obj) { free(obj); }
你可以使用这些低级函数对结构体进行操作
v = new_Vector() Vector_x_set(v, 2) Vector_y_set(v, 10) Vector_z_set(v, -5) ... delete_Vector(v)
Typedef and structures
SWIG支持以下在C程序中很常见的类型定义
typedef struct {
double x, y, z;
} Vector;
此时,SWIG会假定该对象的名称为“ Vector”,并像以前一样创建访问器函数。 唯一的区别是,使用typedef允许SWIG在其生成的代码上删除struct关键字。 例如:
double Vector_x_get(Vector *obj) { return obj->x; }
如果这样使用两个不同的名称
typedef struct vector_struct {
double x, y, z;
} Vector;
使用名称Vector代替vector_struct。 如果稍后在接口中定义的声明使用类型struct vector_struct,则SWIG知道它与Vector相同,并且会生成适当的类型检查代码。
字符串和结构体
涉及字符串的结构需要格外小心。 SWIG假定使用malloc()动态分配了char *类型的所有成员,并且它们都是NULL终止的ASCII字符串。 修改此类成员后,将释放先前的内容,并分配新的内容。
例如:
%module mymodule ... struct Foo { char *name; ... }
这会生成一下访问器函数:
char *Foo_name_get(Foo *obj) { return Foo->name; } char *Foo_name_set(Foo *obj, char *c) { if (obj->name) free(obj->name); obj->name = (char *) malloc(strlen(c)+1); strcpy(obj->name,c); return obj->name; }
如果该行为不能满足与使用不一致,可以使用SWIG memberin类型映射更改
注意:如果使用-c ++选项,则new和delete用于执行内存分配
数组成员
数组可能显示为结构的成员,但它们将是只读的。 SWIG将编写一个访问器函数,该函数将指针返回数组的第一个元素,但不会编写更改数组本身内容的函数。 当检测到这种情况时,SWIG可能会生成警告消息,例如以下内容:
interface.i:116. Warning. Array member will be read-only
结构体数据成员
有时,结构将包含本身就是结构的数据成员。 例如:
typedef struct Foo {
int x;
} Foo;
typedef struct Bar {
int y;
Foo f; /* struct member */
} Bar;
包装结构成员时,除非将 %naturalvar 指令用于更像C ++引用的结构(请参阅C ++成员数据),否则将其作为指针处理。 成员变量作为指针的访问器有效包装如下:
Foo *Bar_f_get(Bar *b) { return &b->f; } void Bar_f_set(Bar *b, Foo *value) { b->f = *value; }
调用时返回Foo *,该种情况前提是SWIG知道数据成员是一个结构体或者类成员
(!!!在使用的过程中,多个结构体中含有相同结构体成员,其都指向同一个指针,这往往是不符合程序设计的)
Bar *b; Foo_x_set(Bar_f_get(b),37);
C构造和析构函数(这部分目前没啥用)
在包装结构时,通常有一种用于创建和销毁对象的机制。
如果您不希望SWIG为您的接口生成默认构造函数,则可以使用%nodefaultctor指令或-nodefaultctor命令行选项。 例如:
swig -nodefaultctor example.i
%module foo ... %nodefaultctor; // Don't create default constructors ... declarations ... %clearnodefaultctor; // Re-enable default constructors
如果需要更精确的控制,%nodefaultctor可以有选择地针对单个结构定义。 例如:
%nodefaultctor Foo; // No default constructor for Foo ... struct Foo { // No default constructor generated. }; struct Bar { // Default constructor generated. };
由于大多数时候忽略隐式或默认析构函数会导致内存泄漏,因此SWIG始终会尝试生成它们。 但是,如果需要,可以使用%nodefaultdtor有选择地禁用默认/隐式析构函数的生成。
%nodefaultdtor Foo; // No default/implicit destructor for Foo ... struct Foo { // No default destructor is generated. }; struct Bar { // Default destructor generated. };
注意:还有-nodefault选项和%nodefault指令,它们会禁用默认或隐式析构函数的生成。 这可能会导致目标语言之间的内存泄漏,强烈建议您不要使用它们。
如何创建新结构体或对象
python调用SWIG封装的接口,只是返回指针,不能new一个出来(目前知道的是这样的)eg:a=t_class(), b=t_class()都是同一个地址,如何创建新对象或结构体呢?
目前我采用的方法是 %include "carrays.i" 用 array_functions方法创建,具体使用参见https://blog.csdn.net/qianshuyuankk/article/details/103051774