欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SWIG使用简明教程(二)

程序员文章站 2024-01-04 21:02:46
...

 

结构体和联合体

如果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

 

 

上一篇:

下一篇: