SWIG 3 中文手冊——9. SWIG 庫


9 SWIG 庫

To help build extension modules, SWIG is packaged with a library of support files that you can include in your own interfaces. These files often define new SWIG directives or provide utility functions that can be used to access parts of the standard C and C++ libraries. This chapter provides a reference to the current set of supported library files.

Compatibility note: Older versions of SWIG included a number of library files for manipulating pointers, arrays, and other structures. Most these files are now deprecated and have been removed from the distribution. Alternative libraries provide similar functionality. Please read this chapter carefully if you used the old libraries.

為了幫助構建擴展模塊,SWIG 附帶了支持文件庫,你可以在自己的接口文件中包含這些支持文件。這些文件通常定義新的 SWIG 指令或提供實用函數,這些函數可用於訪問標准 C 和 C++ 庫的一部分。本章提供對當前支持的庫文件的參考。

注意兼容性:較早版本的 SWIG 包括許多用於處理指針、數組和其他結構體的庫文件。現在大多數這些文件已被棄用,並已從發行版中刪除。備用庫提供類似的功能。如果你使用的是舊庫,請仔細閱讀本章。

9.1 %include 指令與庫搜索路徑

Library files are included using the %include directive. When searching for files, directories are searched in the following order:

  1. The current directory
  2. Directories specified with the -I command line option
  3. ./swig_lib
  4. SWIG library install location as reported by swig -swiglib, for example /usr/local/share/swig/1.3.30
  5. On Windows, a directory Lib relative to the location of swig.exe is also searched.

Within directories mentioned in points 3-5, SWIG first looks for a subdirectory corresponding to a target language (e.g., python, tcl, etc.). If found, SWIG will search the language specific directory first. This allows for language-specific implementations of library files.

You can ignore the installed SWIG library by setting the SWIG_LIBenvironment variable. Set the environment variable to hold an alternative library directory.

The directories that are searched are displayed when using -verbose commandline option.

使用 %include 指令包含庫文件。搜索文件時,將按以下順序搜索目錄:

  1. 當前目錄
  2. -I 命令行選項指定的目錄
  3. ./swig_lib
  4. SWIG 庫的安裝位置(由 swig -swiglib 報告),例如 /usr/local/share/swig/1.3.30
  5. 在 Windows 上,還將搜索相對於 swig.exe 位置的目錄 Lib

在第 3-5 點提到的目錄中,SWIG 首先查找與目標語言相對應的子目錄(例如,pythontcl 等)。如果找到,SWIG 將首先搜索特定語言的目錄。這允許特定語言的庫文件實現。

你可以通過設置 SWIG_LIB 環境變量來忽略已安裝的 SWIG 庫。設置環境變量以保存備用庫目錄。

使用 -verbose 命令行選項時,將顯示搜索到的目錄。

9.2 C 數組與指針

This section describes library modules for manipulating low-level C arrays and pointers. The primary use of these modules is in supporting C declarations that manipulate bare pointers such as int *, double *, or void *. The modules can be used to allocate memory, manufacture pointers, dereference memory, and wrap pointers as class-like objects. Since these functions provide direct access to memory, their use is potentially unsafe and you should exercise caution.

本節描述用於處理低級 C 數組和指針的庫模塊。這些模塊的主要用途是支持 C 聲明,這些聲明可操作諸如 int *double *void * 之類的裸指針。這些模塊可用於分配內存、創建指針、解引用內存以及將指針包裝為類對象。由於這些函數可直接訪問內存,因此使用它們可能不安全,所以要應謹慎行事。

9.2.1 cpointer.i

The cpointer.i module defines macros that can be used to used to generate wrappers around simple C pointers. The primary use of this module is in generating pointers to primitive datatypes such as int and double.

cpointer.i 模塊定義了宏,可用於生成簡單 C 指針的包裝器。這個模塊的主要用途是生成指向原始數據類型,例如 intdouble 的指針。

%pointer_functions(type, name)

Generates a collection of four functions for manipulating a pointer type *:

生成四個用於操作指針 type * 的函數:

type *new_name()

Creates a new object of type type and returns a pointer to it. In C, the object is created using calloc(). In C++, new is used.

創建一個類型為 type 的新對象,並返回一個指向它的指針。在 C 語言中,使用 calloc() 創建對象。在 C++ 中,使用 new

type *copy_name(type value)

Creates a new object of type type and returns a pointer to it. An initial value is set by copying it from value. In C, the object is created using calloc(). In C++, new is used.

創建一個類型為 type 的新對象,並返回一個指向它的指針。通過從 value 中復制值來設置初始值。在 C 語言中,使用 calloc() 創建對象。在 C++ 中,使用 new

type *delete_name(type *obj)

Deletes an object type type.

刪除一個 type 類型的對象。

void name_assign(type *obj, type value)

Assigns *obj = value.

賦值 *obj = value

type name_value(type *obj)

Returns the value of *obj.

When using this macro, type may be any type and name must be a legal identifier in the target language. name should not correspond to any other name used in the interface file.

Here is a simple example of using %pointer_functions():

返回 *obj 的值。

使用此宏時,type 可以是任何類型,而 name 必須是目標語言中的合法標識符。名稱不應該與接口文件中使用的任何其他名稱相對應。

這是一個使用 %pointer_functions() 的簡單示例:

%module example
%include "cpointer.i"

/* Create some functions for working with "int *" */
%pointer_functions(int, intp);

/* A function that uses an "int *" */
void add(int x, int y, int *result);

Now, in Python:

現在,在 Python 中:

>>> import example
>>> c = example.new_intp()     # Create an "int" for storing result
>>> example.add(3, 4, c)       # Call function
>>> example.intp_value(c)      # Dereference
7
>>> example.delete_intp(c)     # Delete

%pointer_class(type, name)

Wraps a pointer of type * inside a class-based interface. This interface is as follows:

在基於類的接口內包裝 type * 指針。該接口如下:

struct name {
  name();                            // Create pointer object
  ~name();                           // Delete pointer object
  void assign(type value);           // Assign value
  type value();                      // Get value
  type *cast();                      // Cast the pointer to original type
  static name *frompointer(type *);  // Create class wrapper from existing
                                     // pointer
};

When using this macro, type is restricted to a simple type name like int, float, or Foo. Pointers and other complicated types are not allowed. name must be a valid identifier not already in use. When a pointer is wrapped as a class, the "class" may be transparently passed to any function that expects the pointer.

If the target language does not support proxy classes, the use of this macro will produce the example same functions as %pointer_functions() macro.

It should be noted that the class interface does introduce a new object or wrap a pointer inside a special structure. Instead, the raw pointer is used directly.

Here is the same example using a class instead:

使用此宏時,type 僅限於一個簡單的類型名稱,例如 intfloatFoo。不允許使用指針和其他復雜類型。name 必須是尚未使用的有效標識符。當將指針包裝為類時,這個類可以透明地傳遞給需要該指針的任何函數。

如果目標語言不支持代理類,則使用此宏將產生與 %pointer_functions() 宏相同的示例函數。

應當注意,類接口確實引入了新對象,或將指針包裝在特殊結構體內。相反,原始指針是直接使用的。

這是使用類的同一示例:

%module example
%include "cpointer.i"

/* Wrap a class interface around an "int *" */
%pointer_class(int, intp);

/* A function that uses an "int *" */
void add(int x, int y, int *result);

Now, in Python (using proxy classes)

現在,在 Python 中(使用代理類)

>>> import example
>>> c = example.intp()         # Create an "int" for storing result
>>> example.add(3, 4, c)       # Call function
>>> c.value()                  # Dereference
7

Of the two macros, %pointer_class is probably the most convenient when working with simple pointers. This is because the pointers are access like objects and they can be easily garbage collected (destruction of the pointer object destroys the underlying object).

在這兩個宏中,%pointer_class 可能是處理簡單指針時最方便的方法。這是因為指針可以像對象一樣被訪問,並且可以很容易地對其進行垃圾回收(指針對象的破壞會破壞基礎對象)。

%pointer_cast(type1, type2, name)

Creates a casting function that converts type1 to type2. The name of the function is name. For example:

創建一個轉換函數,將 type1 轉換為 type2。函數的名稱是 name。例如:

%pointer_cast(int *, unsigned int *, int_to_uint);

In this example, the function int_to_uint() would be used to cast types in the target language.

Note: None of these macros can be used to safely work with strings (char * or char **).

Note: When working with simple pointers, typemaps can often be used to provide more seamless operation.

在此示例中,函數 int_to_uint() 將用於在目標語言中轉換類型。

注意:這些宏均不能安全地處理字符串(char *char **)。

注意:當使用簡單的指針時,類型映射通常可以用來提供更無縫的操作。

9.2.2 carrays.i

This module defines macros that assist in wrapping ordinary C pointers as arrays. The module does not provide any safety or an extra layer of wrapping--it merely provides functionality for creating, destroying, and modifying the contents of raw C array data.

該模塊定義了輔助將普通 C 指針包裝為數組的宏。該模塊不提供任何安全性或額外的包裝層——它僅提供用於創建、銷毀和修改原始 C 數組數據內容的功能。

%array_functions(type, name)

Creates four functions.

創建四個函數。

type *new_name(int nelements)

Creates a new array of objects of type type. In C, the array is allocated using calloc(). In C++, new [] is used.

創建一個類型為 type 的對象的數組。在 C 語言中,使用 calloc() 分配數組。在 C++ 中,使用 new []

type *delete_name(type *ary)

Deletes an array. In C, free() is used. In C++, delete [] is used.

刪除數組。在 C 中使用 free()。在 C++ 中使用 delete []

type name_getitem(type *ary, int index)

Returns the value ary[index].

返回值 ary[index]

void name_setitem(type *ary, int index, type value)

Assigns ary[index] = value.

When using this macro, type may be any type and name must be a legal identifier in the target language. name should not correspond to any other name used in the interface file.

Here is an example of %array_functions(). Suppose you had a function like this:

賦值 ary[index] = value

使用此宏時,type 可以是任何類型,而 name 必須是目標語言中的合法標識符。名稱不應該與接口文件中使用的任何其他名稱相對應。

這是 %array_functions() 的示例。假設你具有如下函數:

void print_array(double x[10]) {
  int i;
  for (i = 0; i < 10; i++) {
    printf("[%d] = %g\n", i, x[i]);
  }
}

To wrap it, you might write this:

要包裝它,你可以這樣寫接口文件:

%module example

%include "carrays.i"
%array_functions(double, doubleArray);

void print_array(double x[10]);

Now, in a scripting language, you might write this:

現在,在腳本語言中,你可以寫這樣的代碼:

a = new_doubleArray(10)             # Create an array
for i in range(0, 10):
    doubleArray_setitem(a, i, 2*i)  # Set a value
print_array(a)                      # Pass to C
delete_doubleArray(a)               # Destroy array

%array_class(type, name)

Wraps a pointer of type * inside a class-based interface. This interface is as follows:

在基於類的接口內包裝 type * 指針。該接口如下:

struct name {
  name(int nelements);                  // Create an array
  ~name();                              // Delete array
  type getitem(int index);              // Return item
  void setitem(int index, type value);  // Set item
  type *cast();                         // Cast to original type
  static name *frompointer(type *);     // Create class wrapper from
                                        // existing pointer
};

When using this macro, type is restricted to a simple type name like int or float. Pointers and other complicated types are not allowed. name must be a valid identifier not already in use. When a pointer is wrapped as a class, it can be transparently passed to any function that expects the pointer.

When combined with proxy classes, the %array_class() macro can be especially useful. For example:

使用此宏時,type 僅限於一個簡單的類型名稱,例如 intfloat。不允許使用指針和其他復雜類型。名稱必須是尚未使用的有效標識符。將指針包裝為類時,可以將其透明地傳遞給任何需要該指針的函數。

當與代理類結合使用時,%array_class() 宏可能會特別有用。例如:

%module example
%include "carrays.i"
%array_class(double, doubleArray);

void print_array(double x[10]);

Allows you to do this:

允許你這樣做:

import example
c = example.doubleArray(10)  # Create double[10]
for i in range(0, 10):
    c[i] = 2*i               # Assign values
example.print_array(c)       # Pass to C

Note: These macros do not encapsulate C arrays inside a special data structure or proxy. There is no bounds checking or safety of any kind. If you want this, you should consider using a special array object rather than a bare pointer.

Note: %array_functions() and %array_class() should not be used with types of char or char *.

注意:這些宏不會將 C 數組封裝進特殊的數據結構或代理類中。沒有邊界檢查或任何形式的安全檢查。如果需要,應該考慮使用特殊的數組對象而不是裸指針。

注意%array_functions()%array_class() 不能和類型 charchar * 共同使用。

9.2.3 cmalloc.i

This module defines macros for wrapping the low-level C memory allocation functions malloc(), calloc(), realloc(), and free().

該模塊定義了用於包裝低級 C 內存分配函數 malloc()calloc()realloc()free() 的宏。

%malloc(type [, name=type])

Creates a wrapper around malloc() with the following prototype:

創建以下原型的 malloc() 包裝器:

type *malloc_name(int nbytes = sizeof(type));

If type is void, then the size parameter nbytes is required. The name parameter only needs to be specified when wrapping a type that is not a valid identifier (e.g., "int *", "double **", etc.).

如果 typevoid,則需要參數 nbytes。僅在包裝不是有效標識符的類型時(例如,int *double ** 等),才需要指定 name 參數。

%calloc(type [, name=type])

Creates a wrapper around calloc() with the following prototype:

創建以下原型的 calloc() 包裝器:

type *calloc_name(int nobj =1, int sz = sizeof(type));

If type is void, then the size parameter sz is required.

如果 typevoid,則需要參數 sz

%realloc(type [, name=type])

Creates a wrapper around realloc() with the following prototype:

創建以下原型的 realloc() 包裝器:

type *realloc_name(type *ptr, int nitems);

Note: unlike the C realloc(), the wrapper generated by this macro implicitly includes the size of the corresponding type. For example, realloc_int(p, 100) reallocates p so that it holds 100 integers.

注意:與 C 中的 realloc() 不同,此宏生成的包裝器隱式包含相應類型的大小。例如,realloc_int(p, 100) 重新分配 p,使其包含 100 個整數。

%free(type [, name=type])

Creates a wrapper around free() with the following prototype:

創建以下原型的 free() 包裝器:

void free_name(type *ptr);

%sizeof(type [, name=type])

Creates the constant:

創建常量:

%constant int sizeof_name = sizeof(type);

%allocators(type [, name=type])

Generates wrappers for all five of the above operations.

Here is a simple example that illustrates the use of these macros:

為上述所有五個操作生成包裝器。

這里有一個簡單的示例,說明了這些宏的用法:

// SWIG interface
%module example
%include "cmalloc.i"

%malloc(int);
%free(int);

%malloc(int *, intp);
%free(int *, intp);

%allocators(double);

Now, in a script:

現在,在腳本中:

>>> from example import *
>>> a = malloc_int()
>>> a
'_000efa70_p_int'
>>> free_int(a)
>>> b = malloc_intp()
>>> b
'_000efb20_p_p_int'
>>> free_intp(b)
>>> c = calloc_double(50)
>>> c
'_000fab98_p_double'
>>> c = realloc_double(100000)
>>> free_double(c)
>>> print sizeof_double
8
>>>

9.2.4 cdata.i

The cdata.i module defines functions for converting raw C data to and from strings in the target language. The primary applications of this module would be packing/unpacking of binary data structures--for instance, if you needed to extract data from a buffer. The target language must support strings with embedded binary data in order for this to work.

cdata.i 模塊定義了將原始 C 數據與目標語言的字符串進行相互轉換的函數。該模塊的主要應用是打包、解包二進制數據結構。例如,如果你需要從緩沖區提取數據。目標語言必須支持帶有嵌入二進制數據的字符串,這樣才能起作用。

const char *cdata(void *ptr, size_t nbytes)

Converts nbytes of data at ptr into a string. ptr can be any pointer.

ptrnbytes 大小的數據轉換成字符串。ptr 可以是任何指針。

void memmove(void *ptr, const char *s)

Copies all of the string data in s into the memory pointed to by ptr. The string may contain embedded NULL bytes. This is actually a wrapper to the standard C library memmove function, which is declared as void memmove(void *ptr, const void *src, size_t n). The src and length n parameters are extracted from the language specific string s in the underlying wrapper code.

One use of these functions is packing and unpacking data from memory. Here is a short example:

s 中的所有字符串數據復制到 ptr 指向的內存中。該字符串可能包含嵌入的 NULL 字節。這實際上是 C 標准庫中 memmove 函數的包裝,該函數被聲明為 void memmove(void *ptr,const void *src,size_t n)srclength 參數是從底層包裝器代碼中特定於語言的字符串 s 中提取的。

這些函數的一種用途是從內存打包和拆包數據。這是一個簡短的示例:

// SWIG interface
%module example
%include "carrays.i"
%include "cdata.i"

%array_class(int, intArray);

Python example:

Python 示例:

>>> a = intArray(10)
>>> for i in range(0, 10):
...    a[i] = i
>>> b = cdata(a, 40)
>>> b
'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04
\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00\t'
>>> c = intArray(10)
>>> memmove(c, b)
>>> print c[4]
4
>>>

Since the size of data is not always known, the following macro is also defined:

由於並不總是知道數據大小,因此還定義了以下宏:

%cdata(type [, name=type])

Generates the following function for extracting C data for a given type.

生成以下函數為給定類型提取 C 數據。

char *cdata_name(type* ptr, int nitems)

nitems is the number of items of the given type to extract.

Note: These functions provide direct access to memory and can be used to overwrite data. Clearly they are unsafe.

nitems 是給定類型要提取的項目數。

注意:這些函數提供對內存的直接訪問,並可用於覆蓋數據。顯然,它們是不安全的。

9.3 C 字符串處理

A common problem when working with C programs is dealing with functions that manipulate raw character data using char *. In part, problems arise because there are different interpretations of char *--it could be a NULL-terminated string or it could point to binary data. Moreover, functions that manipulate raw strings may mutate data, perform implicit memory allocations, or utilize fixed-sized buffers.

The problems (and perils) of using char * are well-known. However, SWIG is not in the business of enforcing morality. The modules in this section provide basic functionality for manipulating raw C strings.

使用 C 程序時,一個常見的問題是處理使用 char * 操作原始字符數據的函數。部分情況下,出現問題是因為對 char * 有不同的解釋——它可以是以 NULL 結尾的字符串,也可以指向二進制數據。此外,操作原始字符串的函數可能會改變數據,執行隱式內存分配或利用固定大小的緩沖區。

使用 char * 的問題(和危險)是眾所周知的。但是,SWIG 並不涉及道德操守。本節中的模塊提供用於處理原始 C 字符串的基本功能。

9.3.1 默認字符串處理

Suppose you have a C function with this prototype:

假設你有一個如下原型的 C 函數:

char *foo(char *s);

The default wrapping behavior for this function is to set s to a raw char * that refers to the internal string data in the target language. In other words, if you were using a language like Tcl, and you wrote this,

該函數的默認包裝行為是將 s 設置為指向目標語言內部字符串數據的原始 char *。換句話說,如果你使用的是 Tcl 這樣的語言,並且你這樣寫腳本,

% foo Hello

then s would point to the representation of "Hello" inside the Tcl interpreter. When returning a char *, SWIG assumes that it is a NULL-terminated string and makes a copy of it. This gives the target language its own copy of the result.

There are obvious problems with the default behavior. First, since a char * argument points to data inside the target language, it is NOT safe for a function to modify this data (doing so may corrupt the interpreter and lead to a crash). Furthermore, the default behavior does not work well with binary data. Instead, strings are assumed to be NULL-terminated.

那么 s 將指向 Tcl 解釋器中 Hello 的表示。當返回 char * 時,SWIG 假定它是一個以 NULL 結尾的字符串,並對其進行復制。這為目標語言提供了自己的結果副本。

默認行為存在明顯的問題。首先,由於 char * 參數指向目標語言內部的數據,因此函數修改該數據是不安全的(這樣做可能會破壞解釋器並導致崩潰)。此外,默認行為不適用於二進制數據,而是假定字符串以 NULL 終止。

9.3.2 傳遞二進制數據

If you have a function that expects binary data,

如果你的函數需要二進制數據,

size_t parity(char *str, size_t len, size_t initial);

you can wrap the parameters (char *str, size_t len) as a single argument using a typemap. Just do this:

你可以使用類型映射將參數 (char * str, size_t len) 包裝為單個參數。即這樣做:

%apply (char *STRING, size_t LENGTH) { (char *str, size_t len) };
...
size_t parity(char *str, size_t len, size_t initial);

Now, in the target language, you can use binary string data like this:

現在,在目標語言中,你可以使用像這樣的二進制字符串數據:

>>> s = "H\x00\x15eg\x09\x20"
>>> parity(s, 0)

In the wrapper function, the passed string will be expanded to a pointer and length parameter. The (char *STRING, int LENGTH) multi-argument typemap is also available in addition to (char *STRING, size_t LENGTH).

在包裝器函數中,傳遞的字符串將擴展為指針和長度參數。除了 (char * STRING, size_t LENGTH) 外,(char * STRING, int LENGTH) 多參數類型映射也是可用的。

9.3.3 使用 %newobject 釋放內存

If you have a function that allocates memory like this,

如果你有一個如下分配內存的函數,

char *foo() {
  char *result = (char *) malloc(...);
  ...
  return result;
}

then the SWIG generated wrappers will have a memory leak--the returned data will be copied into a string object and the old contents ignored.

To fix the memory leak, use the %newobject directive.

那么 SWIG 生成的包裝器將發生內存泄漏,返回的數據將被復制到字符串對象中,而舊內容將被忽略。

要解決內存泄漏,請使用 %newobject 指令。

%newobject foo;
...
char *foo();

This will release the result if the appropriate target language support is available. SWIG provides the appropriate "newfree" typemap for char * so that the memory is released, however, you may need to provide your own "newfree" typemap for other types. See Object ownership and %newobject for more details.

如果目標語言有適當的支持可用,結果將被釋放。SWIG 為 char * 提供了適當的 newfree 類型映射,以便釋放內存,但是,你可能需要為其他類型提供自己的 newfree 類型映射。有關更多詳細信息,請參見對象所有權和 %newobject

9.3.4 cstring.i

The cstring.i library file provides a collection of macros for dealing with functions that either mutate string arguments or which try to output string data through their arguments. An example of such a function might be this rather questionable implementation:

cstring.i 庫文件提供了一組宏,用於處理使字符串參數發生改變或試圖通過其參數輸出字符串數據的函數。這個函數的一個示例可能是這種相當可疑的實現:

void get_path(char *s) {
  // Potential buffer overflow---uh, oh.
  sprintf(s, "%s/%s", base_directory, sub_directory);
}
...
// Somewhere else in the C program
{
  char path[1024];
  ...
  get_path(path);
  ...
}

(Off topic rant: If your program really has functions like this, you would be well-advised to replace them with safer alternatives involving bounds checking).

The macros defined in this module all expand to various combinations of typemaps. Therefore, the same pattern matching rules and ideas apply.

(題外話:如果你的程序確實具有這樣的函數,建議你使用有邊界檢查的更安全的替代方法來替換它們)。

此模塊中定義的宏全部擴展為類型映射的各種組合。因此,適用相同的模式匹配規則和思想。

%cstring_bounded_output(parm, maxsize)

Turns parameter parm into an output value. The output string is assumed to be NULL-terminated and smaller than maxsize characters. Here is an example:

將參數 parm 轉換為輸出值。假設輸出字符串以 NULL 結尾,並且小於 maxsize 個字符。這是一個例子:

%cstring_bounded_output(char *path, 1024);
...
void get_path(char *path);

In the target language:

在目標語言中:

>>> get_path()
/home/beazley/packages/Foo/Bar
>>>

Internally, the wrapper function allocates a small buffer (on the stack) of the requested size and passes it as the pointer value. Data stored in the buffer is then returned as a function return value. If the function already returns a value, then the return value and the output string are returned together (multiple return values). If more than maxsize bytes are written, your program will crash with a buffer overflow!

在內部,包裝器函數會分配一個要求大小的小緩沖區(在堆棧上),並將其作為指針值傳遞。然后將存儲在緩沖區中的數據作為函數返回值返回。如果函數已經返回一個值,則將返回值和輸出字符串一起返回(多個返回值)。如果寫入的字節數超過最大字節數,則程序將因緩沖區溢出而崩潰!

%cstring_chunk_output(parm, chunksize)

Turns parameter parm into an output value. The output string is always chunksize and may contain binary data. Here is an example:

將參數 parm 轉換為輸出值。輸出字符串始終為 chunksize,並且可能包含二進制數據。這是一個例子:

%cstring_chunk_output(char *packet, PACKETSIZE);
...
void get_packet(char *packet);

In the target language:

在目標語言中:

>>> get_packet()
'\xa9Y:\xf6\xd7\xe1\x87\xdbH;y\x97\x7f\xd3\x99\x14V\xec\x06\xea\xa2\x88'
>>>

This macro is essentially identical to %cstring_bounded_output. The only difference is that the result is always chunksize characters. Furthermore, the result can contain binary data. If more than maxsizebytes are written, your program will crash with a buffer overflow!

這個宏在本質上與 %cstring_bounded_output 相同。唯一的區別是結果始終是 chunksize 個字符。此外,結果可以包含二進制數據。如果寫入的字節數超過 maxsizebytes,你的程序將因緩沖區溢出而崩潰!

%cstring_bounded_mutable(parm, maxsize)

Turns parameter parm into a mutable string argument. The input string is assumed to be NULL-terminated and smaller than maxsize characters. The output string is also assumed to be NULL-terminated and less than maxsize characters.

將參數 parm 轉換為可變的字符串參數。假設輸入字符串以 NULL 終止,並且小於 maxsize 字符。還假定輸出字符串以 NULL 終止並且小於 maxsize 個字符。

%cstring_bounded_mutable(char *ustr, 1024);
...
void make_upper(char *ustr);

In the target language:

在目標語言中:

>>> make_upper("hello world")
'HELLO WORLD'
>>>

Internally, this macro is almost exactly the same as %cstring_bounded_output. The only difference is that the parameter accepts an input value that is used to initialize the internal buffer. It is important to emphasize that this function does not mutate the string value passed---instead it makes a copy of the input value, mutates it, and returns it as a result. If more than maxsize bytes are written, your program will crash with a buffer overflow!

在內部,此宏與 %cstring_bounded_output 幾乎完全相同。唯一的區別是參數接受用於初始化內部緩沖區的輸入值。需要強調的是,此函數不會使傳遞來的字符串值發生改變,而是復制輸入值,對其進行改變並作為結果返回。如果寫入的字節數超過最大字節數,則程序將因緩沖區溢出而崩潰!

%cstring_mutable(parm [, expansion])

Turns parameter parm into a mutable string argument. The input string is assumed to be NULL-terminated. An optional parameter expansion specifies the number of extra characters by which the string might grow when it is modified. The output string is assumed to be NULL-terminated and less than the size of the input string plus any expansion characters.

將參數 parm 轉換為可變的字符串參數。假定輸入字符串以 NULL 終止。可選參數 expansion 指定修改字符串時字符串可能增長的額外字符數。假定輸出字符串以 NULL 終止,並且小於輸入字符串的大小加上任何擴展字符。

%cstring_mutable(char *ustr);
...
void make_upper(char *ustr);

%cstring_mutable(char *hstr, HEADER_SIZE);
...
void attach_header(char *hstr);

In the target language:

在目標語言中:

>>> make_upper("hello world")
'HELLO WORLD'
>>> attach_header("Hello world")
'header: Hello world'
>>>

This macro differs from %cstring_bounded_mutable() in that a buffer is dynamically allocated (on the heap using malloc / new). This buffer is always large enough to store a copy of the input value plus any expansion bytes that might have been requested. It is important to emphasize that this function does not directly mutate the string value passed---instead it makes a copy of the input value, mutates it, and returns it as a result. If the function expands the result by more than expansion extra bytes, then the program will crash with a buffer overflow!

這個宏與 %cstring_bounded_mutable() 的不同之處在於動態地分配了一個緩沖區(在堆上使用 mallocnew)。此緩沖區始終足夠大,可以存儲輸入值的副本以及可能已請求的任何擴展字節。需要強調的是,此函數不會直接更改傳遞的字符串值,而是復制輸入值,對其進行更改並返回結果。如果函數將結果擴展多於擴展多余字節,則程序將因緩沖區溢出而崩潰!

%cstring_output_maxsize(parm, maxparm)

This macro is used to handle bounded character output functions where both a char * and a maximum length parameter are provided. As input, a user simply supplies the maximum length. The return value is assumed to be a NULL-terminated string.

該宏用於處理有限制的字符輸出函數,其中提供了 char * 和最大長度參數。作為輸入,用戶只需提供最大長度即可。返回值假定為以 NULL 結尾的字符串。

%cstring_output_maxsize(char *path, int maxpath);
...
void get_path(char *path, int maxpath);

In the target language:

在目標語言中:

>>> get_path(1024)
'/home/beazley/Packages/Foo/Bar'
>>>

This macro provides a safer alternative for functions that need to write string data into a buffer. User supplied buffer size is used to dynamically allocate memory on heap. Results are placed into that buffer and returned as a string object.

對於需要將字符串數據寫入緩沖區的函數,此宏提供了更安全的選擇。用戶提供的緩沖區大小用於在堆上動態分配內存。結果放入該緩沖區中,並作為字符串對象返回。

%cstring_output_withsize(parm, maxparm)

This macro is used to handle bounded character output functions where both a char * and a pointer int * are passed. Initially, the int * parameter points to a value containing the maximum size. On return, this value is assumed to contain the actual number of bytes. As input, a user simply supplies the maximum length. The output value is a string that may contain binary data.

這個宏用於處理有限制的字符輸出函數,其中既傳遞了 char * 指針,又傳遞了指針 int *。最初,int * 參數指向包含最大大小的值。返回時,假定該值包含實際字節數。作為輸入,用戶只需提供最大長度即可。輸出值是一個可能包含二進制數據的字符串。

%cstring_output_withsize(char *data, int *maxdata);
...
void get_data(char *data, int *maxdata);

In the target language:

在目標語言中:

>>> get_data(1024)
'x627388912'
>>> get_data(1024)
'xyzzy'
>>>

This macro is a somewhat more powerful version of %cstring_output_chunk(). Memory is dynamically allocated and can be arbitrary large. Furthermore, a function can control how much data is actually returned by changing the value of the maxparm argument.

這個宏是 %cstring_output_chunk() 的更強大的版本。內存是動態分配的,可以任意大。此外,一個函數可以通過更改 maxparm 參數的值來控制實際返回多少數據。

%cstring_output_allocate(parm, release)

This macro is used to return strings that are allocated within the program and returned in a parameter of type char **. For example:

該宏用於返回在程序內分配的字符串,並以 char ** 類型的參數返回。例如:

void foo(char **s) {
  *s = (char *) malloc(64);
  sprintf(*s, "Hello world\n");
}

The returned string is assumed to be NULL-terminated. release specifies how the allocated memory is to be released (if applicable). Here is an example:

假定返回的字符串以 NULL 終止。release 指定如何釋放分配的內存(如果適用)。這是一個例子:

%cstring_output_allocate(char **s, free(*$1));
...
void foo(char **s);

In the target language:

在目標語言中:

>>> foo()
'Hello world\n'
>>>

%cstring_output_allocate_size(parm, szparm, release)

This macro is used to return strings that are allocated within the program and returned in two parameters of type char ** and int *. For example:

該宏用於返回在程序中分配的字符串,並以 char **int * 類型的兩個參數返回。例如:

void foo(char **s, int *sz) {
  *s = (char *) malloc(64);
  *sz = 64;
  // Write some binary data
  ...
}

The returned string may contain binary data. release specifies how the allocated memory is to be released (if applicable). Here is an example:

返回的字符串可能包含二進制數據。release 指定釋放分配的內存的方式(如果適用)。這是一個例子:

%cstring_output_allocate_size(char **s, int *slen, free(*$1));
...
void foo(char **s, int *slen);

In the target language:

在目標語言中:

>>> foo()
'\xa9Y:\xf6\xd7\xe1\x87\xdbH;y\x97\x7f\xd3\x99\x14V\xec\x06\xea\xa2\x88'
>>>

This is the safest and most reliable way to return binary string data in SWIG. If you have functions that conform to another prototype, you might consider wrapping them with a helper function. For example, if you had this:

這是在 SWIG 中返回二進制字符串數據的最安全、最可靠的方法。如果你具有符合另一個原型的函數,則可以考慮使用輔助函數將它們包裝起來。例如,如果你有:

char *get_data(int *len);

You could wrap it with a function like this:

你可以用這樣一個函數包裝它:

void my_get_data(char **result, int *len) {
  *result = get_data(len);
}

Comments:

  • Support for the cstring.i module depends on the target language. Not all SWIG modules currently support this library.
  • Reliable handling of raw C strings is a delicate topic. There are many ways to accomplish this in SWIG. This library provides support for a few common techniques.
  • If used in C++, this library uses new and delete [] for memory allocation. If using ANSI C, the library uses malloc() and free().
  • Rather than manipulating char * directly, you might consider using a special string structure or class instead.

評論:

  • cstring.i 模塊的支持取決於目標語言。當前,並非所有的 SWIG 模塊都支持該庫。
  • 可靠地處理原始 C 字符串是一個微妙的話題。在 SWIG 中有許多方法可以完成此操作。該庫提供對一些常用技術的支持。
  • 如果在 C++ 中使用,該庫使用 newdelete [] 進行內存分配。如果使用 ANSI C,該庫將使用 malloc()free()
  • 你可以考慮使用特殊的字符串結構或類,而不是直接操作 char *

9.4 STL/C++ 庫

The library modules in this section provide access to parts of the standard C++ library including the STL. SWIG support for the STL is an ongoing effort. Support is quite comprehensive for some language modules but some of the lesser used modules do not have quite as much library code written.

The following table shows which C++ classes are supported and the equivalent SWIG interface library file for the C++ library.

本節中的庫模塊提供對 C++ 標准庫(包括 STL)的某些部分的訪問。SWIG 對 STL 的支持是一項持續的工作。對某些語言模塊的支持非常全面,但是一些使用較少的模塊沒有編寫太多的庫代碼。

下表顯示了支持的 C++ 類以及 C++ 庫的對等 SWIG 接口庫文件。

C++ class C++ Library file SWIG Interface library file
std::auto_ptr memory std_auto_ptr.i
std::deque deque std_deque.i
std::list list std_list.i
std::map map std_map.i
std::pair utility std_pair.i
std::set set std_set.i
std::string string std_string.i
std::vector vector std_vector.i
std::array array (C++11) std_array.i
std::shared_ptr shared_ptr (C++11) std_shared_ptr.i

The list is by no means complete; some language modules support a subset of the above and some support additional STL classes. Please look for the library files in the appropriate language library directory.

清單絕不完整,一些語言模塊支持上述內容的子集,而某些語言模塊支持其他 STL 類。請在適當的語言庫目錄中查找庫文件。

9.4.1 std::string

The std_string.i library provides typemaps for converting C++ std::string objects to and from strings in the target scripting language. For example:

std_string.i 庫提供了用於將 C++ std::string 對象與目標腳本語言中的字符串進行相互轉換的類型映射。例如:

%module example
%include "std_string.i"

std::string foo();
void        bar(const std::string &x);

In the target language:

在目標語言中:

x = foo()                # Returns a string object
bar("Hello World")       # Pass string as std::string

A common problem that people encounter is that of classes/structures containing a std::string. This can be overcome by defining a typemap. For example:

人們遇到的一個常見問題是包含 std::string 的類或結構體的問題。這可以通過定義類型映射來克服。例如:

%module example
%include "std_string.i"

%apply const std::string& {std::string* foo};

struct my_struct
{
  std::string foo;
};

In the target language:

在目標語言中:

x = my_struct()
x.foo="Hello World"       # assign with string
print x.foo               # print as string

This module only supports types std::string and const std::string &. Pointers and non-const references are left unmodified and returned as SWIG pointers.

This library file is fully aware of C++ namespaces. If you export std::string or rename it with a typedef, make sure you include those declarations in your interface. For example:

該模塊僅支持類型 std::stringconst std::string &。指針和非常引用保持不變,並作為 SWIG 指針返回。

該庫文件完全了解 C++ 命名空間。如果導出 std::string 或使用 typedef 重命名,請確保在接口中包含這些聲明。例如:

%module example
%include "std_string.i"

using namespace std;
typedef std::string String;
...
void foo(string s, const String &t);     // std_string typemaps still applied

9.4.2 std::vector

The std_vector.i library provides support for the C++ std::vector class in the STL. Using this library involves the use of the %template directive. All you need to do is to instantiate different versions of vector for the types that you want to use. For example:

std_vector.i 庫為 STL 中的 C++ std::vector 類提供了支持。使用這個庫需要使用 %template 指令。你要做的就是為要使用的類型實例化不同版本的 vector。例如:

%module example
%include "std_vector.i"

namespace std {
  %template(vectori) vector<int>;
  %template(vectord) vector<double>;
};

When a template vector<X> is instantiated a number of things happen:

  • A class that exposes the C++ API is created in the target language. This can be used to create objects, invoke methods, etc. This class is currently a subset of the real STL vector class.
  • Input typemaps are defined for vector<X>, const vector<X> &, and const vector<X> *. For each of these, a pointer vector<X> * may be passed or a native list object in the target language.
  • An output typemap is defined for vector<X>. In this case, the values in the vector are expanded into a list object in the target language.
  • For all other variations of the type, the wrappers expect to receive a vector<X> * object in the usual manner.
  • An exception handler for std::out_of_range is defined.
  • Optionally, special methods for indexing, item retrieval, slicing, and element assignment may be defined. This depends on the target language.

To illustrate the use of this library, consider the following functions:

當模板 vector<X> 被實例化時,會發生很多事情:

  • 在目標語言中創建暴露 C++ API 的類。它可以用於創建對象、調用方法等。此類當前是真實 STL vector 類的子集。
  • 輸入類型映射是為 vector<X>const vector<X>&const vector<X> * 定義的。對於其中的每一個,可以傳遞指針 vector<X> * 或目標語言中的原生列表對象。
  • vector<X> 定義了一個輸出類型映射。在這種情況下,向量中的值將擴展為目標語言中的列表對象。
  • 對於所有其他類型的包裝,包裝器希望以通常的方式接收一個 vector<X> * 對象。
  • std::out_of_range 定義了一個異常處理。
  • 額外地,可以定義用於索引、項目檢索、切片和元素分配的特殊方法。這取決於目標語言。

為了說明此庫的用法,請考慮以下函數:

/* File : example.h */

#include <vector>
#include <algorithm>
#include <functional>
#include <numeric>

double average(std::vector<int> v) {
  return std::accumulate(v.begin(), v.end(), 0.0)/v.size();
}

std::vector<double> half(const std::vector<double>& v) {
  std::vector<double> w(v);
  for (unsigned int i=0; i<w.size(); i++)
    w[i] /= 2.0;
  return w;
}

void halve_in_place(std::vector<double>& v) {
  std::transform(v.begin(), v.end(), v.begin(),
                 std::bind2nd(std::divides<double>(), 2.0));
}

To wrap with SWIG, you might write the following:

用 SWIG 包裝,你可以這樣寫接口文件:

%module example
%{
#include "example.h"
%}

%include "std_vector.i"
// Instantiate templates used by example
namespace std {
  %template(IntVector) vector<int>;
  %template(DoubleVector) vector<double>;
}

// Include the header file with above prototypes
%include "example.h"

Now, to illustrate the behavior in the scripting interpreter, consider this Python example:

現在,為了說明腳本解釋器中的行為,請考慮以下 Python 示例:

>>> from example import *
>>> iv = IntVector(4)         # Create an vector<int>
>>> for i in range(0, 4):
...      iv[i] = i
>>> average(iv)               # Call method
1.5
>>> average([0, 1, 2, 3])        # Call with list
1.5
>>> half([1, 2, 3])             # Half a list
(0.5, 1.0, 1.5)
>>> halve_in_place([1, 2, 3])   # Oops
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: Type error. Expected _p_std__vectorTdouble_t
>>> dv = DoubleVector(4)
>>> for i in range(0, 4):
...       dv[i] = i
>>> halve_in_place(dv)       # Ok
>>> for i in dv:
...       print i
...
0.0
0.5
1.0
1.5
>>> dv[20] = 4.5
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "example.py", line 81, in __setitem__
    def __setitem__(*args): return apply(examplec.DoubleVector___setitem__, args)
IndexError: vector index out of range
>>>

This library module is fully aware of C++ namespaces. If you use vectors with other names, make sure you include the appropriate using or typedef directives. For example:

該庫模塊完全了解 C++ 命名空間。如果你使用帶有其他名稱的向量,請確保包括適當的 usingtypedef 指令。例如:

%include "std_vector.i"

namespace std {
  %template(IntVector) vector<int>;
}

using namespace std;
typedef std::vector Vector;

void foo(vector<int> *x, const Vector &x);

Note: This module makes use of several advanced SWIG features including templatized typemaps and template partial specialization. If you are trying to wrap other C++ code with templates, you might look at the code contained in std_vector.i. Alternatively, you can show them the code if you want to make their head explode.

Note: This module is defined for all SWIG target languages. However argument conversion details and the public API exposed to the interpreter vary.

注意:該模塊利用了幾種高級 SWIG 功能,包括模板化的類型映射和模板的偏特化。如果你嘗試使用模板包裝其他 C++ 代碼,則可以查看 std_vector.i 中包含的代碼。或者,如果你想讓他們的腦袋爆炸,則可以向他們展示代碼。

注意:該模塊是為所有 SWIG 目標語言定義的。但是,參數轉換的詳細信息和解釋器公開的公共 API 有所不同。

9.4.3 STL 異常

Many of the STL wrapper functions add parameter checking and will throw a language dependent error/exception should the values not be valid. The classic example is array bounds checking. The library wrappers are written to throw a C++ exception in the case of error. The C++ exception in turn gets converted into an appropriate error/exception for the target language. By and large this handling should not need customising, however, customisation can easily be achieved by supplying appropriate "throws" typemaps. For example:

許多 STL 包裝器函數都會添加參數檢查,如果值無效,則會拋出與語言有關的錯誤或異常。經典示例是數組邊界檢查。庫包裝程序被編寫為在發生錯誤的情況下引發 C++ 異常。反過來,C++ 異常會轉換為目標語言的相應錯誤或異常。總的來說,這種處理不需要定制,但是,可以通過提供適當的 throw 類型映射來輕松實現定制。例如:

%module example
%include "std_vector.i"
%typemap(throws) std::out_of_range {
  // custom exception handler
}
%template(VectInt) std::vector<int>;

The custom exception handler might, for example, log the exception then convert it into a specific error/exception for the target language.

When using the STL it is advisable to add in an exception handler to catch all STL exceptions. The %exception directive can be used by placing the following code before any other methods or libraries to be wrapped:

自定義異常處理程序可能是記錄異常,然后將其轉換為目標語言的特定錯誤或異常。

使用 STL 時,建議添加一個異常處理程序以捕獲所有 STL 異常。通過將以下代碼放在任何其他要包裝的方法或庫之前,可以使用 %exception 指令:

%include "exception.i"

%exception {
  try {
    $action
  } catch (const std::exception& e) {
    SWIG_exception(SWIG_RuntimeError, e.what());
  }
}

Any thrown STL exceptions will then be gracefully handled instead of causing a crash.

然后將妥善處理所有引發的 STL 異常,而不會導致崩潰。

9.4.4 shared_ptr 智能指針

Some target languages have support for handling the shared_ptr reference counted smart pointer. This smart pointer is available in the standard C++11 library as std::shared_ptr. It was also in TR1 as std::tr1::shared_ptr before it was fully standardized. Support for the widely used boost::shared_ptr is also available.

In order to use std::shared_ptr, the std_shared_ptr.i library file should be included:

一些目標語言支持處理 shared_ptr 引用計數智能指針。該智能指針在標准 C++11 庫中以 std::shared_ptr 的形式提供。在 TR1 中,它在完全標准化之前還以 std::tr1::shared_ptr 的形式出現。也支持廣泛使用的 boost::shared_ptr

為了使用 std::shared_ptr,要包含 std_shared_ptr.i 庫文件:

%include <std_shared_ptr.i>

The pre-standard std::tr1::shared_ptr can be used by including the following macro before including the std_shared_ptr.i library file:

在包含 std_shared_ptr.i 庫文件之前包含以下宏,可以使用准標准的 std::tr1::shared_ptr

#define SWIG_SHARED_PTR_SUBNAMESPACE tr1
%include <std_shared_ptr.i>

In order to use boost::shared_ptr, the boost_shared_ptr.i library file should be included:

為了使用 boost::shared_ptr,要包含 boost_shared_ptr.i 庫文件:

%include <boost_shared_ptr.i>

You can only use one of these variants of shared_ptr in your interface file at a time. and all three variants must be used in conjunction with the %shared_ptr(T) macro, where T is the underlying pointer type equating to usage shared_ptr<T>. The type T must be non-primitive. A simple example demonstrates usage:

你只能在接口文件中使用 shared_ptr 的這些變體中的一個。並且所有三個變體都必須與 %shared_ptr(T) 宏結合使用,其中 T 是基礎指針類型,等同於用法 shared_ptr<T>。類型 T 必須是非原始的。一個簡單的示例演示用法:

%module example
%include <boost_shared_ptr.i>
%shared_ptr(IntValue)

%inline %{
#include <boost/shared_ptr.hpp>

struct IntValue {
  int value;
  IntValue(int v) : value(v) {}
};

static int extractValue(const IntValue &t) {
  return t.value;
}

static int extractValueSmart(boost::shared_ptr<IntValue> t) {
  return t->value;
}
%}

Note that the %shared_ptr(IntValue) declaration occurs after the inclusion of the boost_shared_ptr.i library which provides the macro and, very importantly, before any usage or declaration of the type, IntValue. The %shared_ptr macro provides, a few things for handling this smart pointer, but mostly a number of typemaps. These typemaps override the default typemaps so that the underlying proxy class is stored and passed around as a pointer to a shared_ptr instead of a plain pointer to the underlying type. This approach means that any instantiation of the type can be passed to methods taking the type by value, reference, pointer or as a smart pointer. The interested reader might want to look at the generated code, however, usage is simple and no different handling is required from the target language. For example, a simple use case of the above code from Java would be:

請注意,%shared_ptr(IntValue) 聲明是在包含提供宏的 boost_shared_ptr.i 庫之后出現的,並且非常重要的是,在使用或聲明類型 IntValue 之前出現。%shared_ptr 宏提供了一些用於處理此智能指針的內容,但主要是許多類型映射。這些類型映射會覆蓋默認的類型映射,以便存儲和傳遞底層代理類,作為指向 shared_ptr 的指針,而不是指向底層類型的普通指針。這種方法意味着該類型的任何實例都可以通過值、引用、指針或作為智能指針傳遞給采用該類型的方法。有興趣的讀者可能想看一下生成的代碼,但是,用法很簡單,不需要與目標語言進行不同的處理。例如,上述來自 Java 的代碼的簡單用例將是:

IntValue iv = new IntValue(1234);
int val1 = example.extractValue(iv);
int val2 = example.extractValueSmart(iv);
System.out.println(val1 + " " + val2);

This shared_ptr library works quite differently to SWIG's normal, but somewhat limited, smart pointer handling. The shared_ptr library does not generate extra wrappers, just for smart pointer handling, in addition to the proxy class. The normal proxy class including inheritance relationships is generated as usual. The only real change introduced by the %shared_ptr macro is that the proxy class stores a pointer to the shared_ptr instance instead of a raw pointer to the instance. A proxy class derived from a base which is being wrapped with shared_ptr can and must be wrapped as a shared_ptr too. In other words all classes in an inheritance hierarchy must all be used with the %shared_ptr macro. For example the following code can be used with the base class shown earlier:

這個 shared_ptr 庫的工作方式與 SWIG 的正常方法有所不同,但受到限制,智能指針處理。除了代理類之外,shared_ptr 庫不會生成其他包裝,僅用於智能指針處理。包括繼承關系的普通代理類照常生成。%shared_ptr 宏引入的唯一真正的變化是代理類存儲指向 shared_ptr 實例的指針,而不是指向該實例的原始指針。從基類派生的代理類和 shared_ptr 一起被包裝,也必須被包裝為 shared_ptr。換句話說,繼承層次結構中的所有類都必須與 %shared_ptr 宏一起使用。例如,以下代碼可與前面顯示的基類一起使用:

%shared_ptr(DerivedIntValue)
%inline %{
struct DerivedIntValue : IntValue {
  DerivedIntValue(int value) : IntValue(value) {}
  ...
};
%}

A shared_ptr of the derived class can now be passed to a method where the base is expected in the target language, just as it can in C++:

現在可以將派生類的 shared_ptr 傳遞給目標語言(如 C++ 中一樣)的方法:

DerivedIntValue div = new DerivedIntValue(5678);
int val3 = example.extractValue(div);
int val4 = example.extractValueSmart(div);

If the %shared_ptr macro is omitted for any class in the inheritance hierarchy, SWIG will warn about this and the generated code may or may not result in a C++ compilation error. For example, the following input:

如果繼承層次結構中的任何類都省略了 %shared_ptr 宏,SWIG 將對此發出警告,並且所生成的代碼可能會,也可能不會導致 C++ 編譯錯誤。例如,以下輸入:

%include "boost_shared_ptr.i"
%shared_ptr(Parent);

%inline %{
  #include <boost/shared_ptr.hpp>
  struct GrandParent {
    virtual ~GrandParent() {}
  };

  struct Parent : GrandParent {
    virtual ~Parent() {}
  };

  struct Child : Parent {
    virtual ~Child() {}
  };
%}

warns about the missing smart pointer information:

警告缺少智能指針的消息:

example.i:12: Warning 520: Base class 'GrandParent' of 'Parent' is not similarly marked as a smart pointer.
example.i:16: Warning 520: Derived class 'Child' of 'Parent' is not similarly marked as a smart pointer.

Adding the missing %shared_ptr macros will fix this:

添加缺少的 %shared_ptr 宏將解決此問題:

%include "boost_shared_ptr.i"
%shared_ptr(GrandParent);
%shared_ptr(Parent);
%shared_ptr(Child);

... as before ...

Note: There is somewhat limited support for %shared_ptr and the director feature and the degrees of success varies among the different target languages. Please help to improve this support by providing patches with improvements.

注意:對 %shared_ptr 和導向器(director)功能的支持有限,成功的程度因不同的目標語言而異。請通過提供具有改進功能的補丁來幫助改善此支持。

9.4.5 auto_ptr 智能指針

While std::auto_ptr is deprecated in C++11, some existing code may still be using it, so SWIG provides limited support for this class: std_auto_ptr.i defines the typemaps which apply to the functions returning objects of this type. Any other use of std_auto_ptr.i is not directly supported.

A typical example of use would be

盡管在 C++11 中不推薦使用 std::auto_ptr,但是某些現有代碼可能仍在使用它,因此 SWIG 對此類提供了有限的支持:std_auto_ptr.i 定義了適用於返回此類型對象的函數的類型映射。不直接支持對 std_auto_ptr.i 的任何其他使用。

使用的典型示例是

%include <std_auto_ptr.i>

%auto_ptr(Klass)
%inline %{
class Klass {
public:
  // Factory function creating objects of this class:
  static std::auto_ptr<Klass> Create(int value) {
    return std::auto_ptr<Klass>(new Klass(value));
  }

  int getValue() const { return m_value; }

private:
  DerivedIntValue(int value) : m_value(value) {}
  int m_value;
};
%}

The returned objects can be used naturally from the target language, e.g. from C#:

返回的對象可以自然地從目標語言使用,例如來自 C#:

Klass k = Klass.Create(17);
int value = k.getValue();

9.5 實用函數庫

9.5.1 exception.i

The exception.i library provides a language-independent function for raising a run-time exception in the target language. This library is largely used by the SWIG library writers. If possible, use the error handling scheme available to your target language as there is greater flexibility in what errors/exceptions can be thrown.

exception.i 庫提供了一種獨立於語言的函數,用於在目標語言中引發運行時異常。SWIG 庫作者主要使用此庫。如果可能,請使用適用於你的目標語言的錯誤處理方案,因為在引發什么錯誤或異常方面具有更大的靈活性。

SWIG_exception(int code, const char *message)

Raises an exception in the target language. code is one of the following symbolic constants:

在目標語言中引發異常。code 是以下符號常量之一:

SWIG_MemoryError
SWIG_IOError
SWIG_RuntimeError
SWIG_IndexError
SWIG_TypeError
SWIG_DivisionByZero
SWIG_OverflowError
SWIG_SyntaxError
SWIG_ValueError
SWIG_SystemError

message is a string indicating more information about the problem.

The primary use of this module is in writing language-independent exception handlers. For example:

message 是一個字符串,指示有關該問題的更多信息。

該模塊的主要用途是編寫獨立於語言的異常處理程序。例如:

%include "exception.i"
%exception std::vector::getitem {
  try {
    $action
  } catch (std::out_of_range& e) {
    SWIG_exception(SWIG_IndexError, const_cast<char*>(e.what()));
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM