# 11 类型映射

## 11.1 引言

Chances are, you are reading this chapter for one of two reasons; you either want to customize SWIG's behavior or you overheard someone mumbling some incomprehensible drivel about "typemaps" and you asked yourself "typemaps, what are those?" That said, let's start with a short disclaimer that "typemaps" are an advanced customization feature that provide direct access to SWIG's low-level code generator. Not only that, they are an integral part of the SWIG C++ type system (a non-trivial topic of its own). Typemaps are generally not a required part of using SWIG. Therefore, you might want to re-read the earlier chapters if you have found your way to this chapter with only a vague idea of what SWIG already does by default.

### 11.1.1 类型转换

One of the most important problems in wrapper code generation is the conversion or marshalling of datatypes between programming languages. Specifically, for every C/C++ declaration, SWIG must somehow generate wrapper code that allows values to be passed back and forth between languages. Since every programming language represents data differently, this is not a simple of matter of simply linking code together with the C linker. Instead, SWIG has to know something about how data is represented in each language and how it can be manipulated.

To illustrate, suppose you had a simple C function like this:

int factorial(int n);


To access this function from Python, a pair of Python API functions are used to convert integer values. For example:

long PyInt_AsLong(PyObject *obj);      /* Python --> C */
PyObject *PyInt_FromLong(long x);      /* C --> Python */


The first function is used to convert the input argument from a Python integer object to C long. The second function is used to convert a value from C back into a Python integer object.

Inside the wrapper function, you might see these functions used like this:

PyObject *wrap_factorial(PyObject *self, PyObject *args) {
int       arg1;
int       result;
PyObject *obj1;
PyObject *resultobj;

if (!PyArg_ParseTuple("O:factorial", &obj1)) return NULL;
arg1 = PyInt_AsLong(obj1);
result = factorial(arg1);
resultobj = PyInt_FromLong(result);
return resultobj;
}


Every target language supported by SWIG has functions that work in a similar manner. For example, in Perl, the following functions are used:

SWIG 支持的每种目标语言都具有以类似方式工作的函数。例如，在 Perl 中，使用以下函数：

IV SvIV(SV *sv);                     /* Perl --> C */
void sv_setiv(SV *sv, IV val);       /* C --> Perl */


In Tcl:

int Tcl_GetLongFromObj(Tcl_Interp *interp, Tcl_Obj *obj, long *value);
Tcl_Obj *Tcl_NewIntObj(long value);


The precise details are not so important. What is important is that all of the underlying type conversion is handled by collections of utility functions and short bits of C code like this--you simply have to read the extension documentation for your favorite language to know how it works (an exercise left to the reader).

### 11.1.2 类型映射

Since type handling is so central to wrapper code generation, SWIG allows it to be completely defined (or redefined) by the user. To do this, a special %typemap directive is used. For example:

/* Convert from Python --> C */
%typemap(in) int {
$1 = PyInt_AsLong($input);
}

/* Convert from C --> Python */
%typemap(out) int {
$result = PyInt_FromLong($1);
}


At first glance, this code will look a little confusing. However, there is really not much to it. The first typemap (the "in" typemap) is used to convert a value from the target language to C. The second typemap (the "out" typemap) is used to convert in the other direction. The content of each typemap is a small fragment of code that is inserted directly into the SWIG generated wrapper functions. The code is usually C or C++ code which will be generated into the C/C++ wrapper functions. Note that this isn't always the case as some target language modules allow target language code within the typemaps which gets generated into target language specific files. Within this code, a number of special variables prefixed with a $ are expanded. These are really just placeholders for C/C++ variables that are generated in the course of creating the wrapper function. In this case, $input refers to an input object that needs to be converted to C/C++ and $result refers to an object that is going to be returned by a wrapper function. $1 refers to a C/C++ variable that has the same type as specified in the typemap declaration (an int in this example).

A short example might make this a little more clear. If you were wrapping a function like this:

int gcd(int x, int y);


A wrapper function would look approximately like this:

PyObject *wrap_gcd(PyObject *self, PyObject *args) {
int arg1;
int arg2;
int result;
PyObject *obj1;
PyObject *obj2;
PyObject *resultobj;

if (!PyArg_ParseTuple("OO:gcd", &obj1, &obj2)) return NULL;

/* "in" typemap, argument 1 */
{
arg1 = PyInt_AsLong(obj1);
}

/* "in" typemap, argument 2 */
{
arg2 = PyInt_AsLong(obj2);
}

result = gcd(arg1, arg2);

/* "out" typemap, return value */
{
resultobj = PyInt_FromLong(result);
}

return resultobj;
}


In this code, you can see how the typemap code has been inserted into the function. You can also see how the special $ variables have been expanded to match certain variable names inside the wrapper function. This is really the whole idea behind typemaps--they simply let you insert arbitrary code into different parts of the generated wrapper functions. Because arbitrary code can be inserted, it possible to completely change the way in which values are converted. 在此代码中，你可以看到如何将类型映射代码插入到函数中。你还可以看到特殊的 $ 变量是如何扩展的，以匹配包装器函数中的某些变量名称。这实际上就是类型映射背后的全部思想，它们只是让你将任意代码插入生成的包装器函数的不同部分。由于可以插入任意代码，因此可以完全改变值转换的方式。

### 11.1.3 模式匹配

As the name implies, the purpose of a typemap is to "map" C datatypes to types in the target language. Once a typemap is defined for a C datatype, it is applied to all future occurrences of that type in the input file. For example:

/* Convert from Perl --> C */
%typemap(in) int {
$1 = SvIV($input);
}

...
int factorial(int n);
int gcd(int x, int y);
int count(char *s, char *t, int max);


The matching of typemaps to C datatypes is more than a simple textual match. In fact, typemaps are fully built into the underlying type system. Therefore, typemaps are unaffected by typedef, namespaces, and other declarations that might hide the underlying type. For example, you could have code like this:

/* Convert from Ruby--> C */
%typemap(in) int {
$1 = NUM2INT($input);
}
...
typedef int Integer;
namespace foo {
typedef Integer Number;
};

int foo(int x);
int bar(Integer y);
int spam(foo::Number a, foo::Number b);


In this case, the typemap is still applied to the proper arguments even though typenames don't always match the text "int". This ability to track types is a critical part of SWIG--in fact, all of the target language modules work merely define a set of typemaps for the basic types. Yet, it is never necessary to write new typemaps for typenames introduced by typedef.

In addition to tracking typenames, typemaps may also be specialized to match against a specific argument name. For example, you could write a typemap like this:

%typemap(in) double nonnegative {
$1 = PyFloat_AsDouble($input);
if ($1 < 0) { PyErr_SetString(PyExc_ValueError, "argument must be nonnegative."); SWIG_fail; } } ... double sin(double x); double cos(double x); double sqrt(double nonnegative); typedef double Real; double log(Real nonnegative); ...  For certain tasks such as input argument conversion, typemaps can be defined for sequences of consecutive arguments. For example: 对于某些任务，例如输入参数转换，可以为连续参数序列定义类型映射。例如： %typemap(in) (char *str, int len) {$1 = PyString_AsString($input); /* char *str */$2 = PyString_Size($input); /* int len */ } ... int count(char *str, int len, char c);  In this case, a single input object is expanded into a pair of C arguments. This example also provides a hint to the unusual variable naming scheme involving $1, $2, and so forth. 在这种情况下，单个输入对象将扩展为一对 C 参数。这个例子也暗示了涉及不寻常的变量命名方案，包括 $1$2 等等。 ### 11.1.4 复用类型映射 Typemaps are normally defined for specific type and argument name patterns. However, typemaps can also be copied and reused. One way to do this is to use assignment like this: 类型映射通常为特定的类型和参数名称模式而定义。但是，类型映射也可以复制和重用。一种方法是使用赋值： %typemap(in) Integer = int; %typemap(in) (char *buffer, int size) = (char *str, int len);  A more general form of copying is found in the %apply directive like this: %apply 指令中可以找到更通用的复制形式，如下所示： %typemap(in) int { /* Convert an integer argument */ ... } %typemap(out) int { /* Return an integer value */ ... } /* Apply all of the integer typemaps to size_t */ %apply int { size_t };  %apply merely takes all of the typemaps that are defined for one type and applies them to other types. Note: you can include a comma separated set of types in the {...} part of %apply. It should be noted that it is not necessary to copy typemaps for types that are related by typedef. For example, if you have this, %apply 仅接受为一种类型定义的所有类型映射，并将它们应用于其他类型。注意：你可以在 %apply{...} 部分中包含一组用逗号分隔的类型。 应该注意的是，没有必要为 typedef 相关的类型复制类型映射。例如，如果你有这个， typedef int size_t;  then SWIG already knows that the int typemaps apply. You don't have to do anything. 那么 SWIG 已经知道了 int 的类型映射。你不必做任何事情。 ### 11.1.5 类型映射能干什么？ The primary use of typemaps is for defining wrapper generation behavior at the level of individual C/C++ datatypes. There are currently six general categories of problems that typemaps address: 类型映射的主要用途是在单一 C/C++ 数据类型级别上定义包装器生成行为。当前，类型映射解决了六大类问题： Argument handling 参数处理 int foo(int x, double y, char *s);  • Input argument conversion ("in" typemap). • Input argument type checking for types used in overloaded methods ("typecheck" typemap). • Output argument handling ("argout" typemap). • Input argument value checking ("check" typemap). • Input argument initialization ("arginit" typemap). • Default arguments ("default" typemap). • Input argument resource management ("freearg" typemap). • 输入参数转换（in 类型映射）。 • 重载方法中的输入参数类型检查（typecheck 类型映射）。 • 输出参数处理（argout 类型映射）。 • 输入参数值检查（check 类型映射）。 • 输入参数初始化（arginit 类型映射）。 • 默认参数（default 类型映射）。 • 输入参数资源管理（freearg 类型映射）。 Return value handling 返回值处理 int foo(int x, double y, char *s);  • Function return value conversion ("out" typemap). • Return value resource management ("ret" typemap). • Resource management for newly allocated objects ("newfree" typemap). • 函数返回值转换（out 类型映射）。 • 返回值资源管理（ret 类型映射）。 • 新分配对象的资源管理（newfree 类型映射）。 Exception handling 异常处理 int foo(int x, double y, char *s) throw(MemoryError, IndexError);  • Handling of C++ exception specifications. ("throw" typemap). • 处理 C++ 异常规范。（throw 类型映射）。 Global variables 全局变量 int foo;  • Assignment of a global variable. ("varin" typemap). • Reading a global variable. ("varout" typemap). • 分配全局变量。（varin 类型映射）。 • 读取全局变量。（varout 类型映射）。 Member variables 成员变量 struct Foo { int x[20]; };  • Assignment of data to a class/structure member. ("memberin" typemap). • 将数据分配给类或结构体成员。（memberin 类型映射）。 Constant creation 创建常量 #define FOO 3 %constant int BAR = 42; enum { ALE, LAGER, STOUT };  • Creation of constant values. ("consttab" or "constcode" typemap). Details of each of these typemaps will be covered shortly. Also, certain language modules may define additional typemaps that expand upon this list. For example, the Java module defines a variety of typemaps for controlling additional aspects of the Java bindings. Consult language specific documentation for further details. • 创建常数值。（consttabconstcode 类型映射）。 每个类型映射的详细内容很快会提到。同样，某些语言模块可能会定义其他类型映射以扩展此列表。例如，Java 模块定义了各种类型映射来控制 Java 绑定的其他方面。请查阅特定于语言的文档以获取更多详细信息。 ### 11.1.6 类型映射不能干什么？ Typemaps can't be used to define properties that apply to C/C++ declarations as a whole. For example, suppose you had a declaration like this, 类型映射不能用于定义整体上适用于 C/C++ 声明的属性。例如，假设你有一个这样的声明， Foo *make_Foo(int n);  and you wanted to tell SWIG that make_Foo(int n) returned a newly allocated object (for the purposes of providing better memory management). Clearly, this property of make_Foo(int n) is not a property that would be associated with the datatype Foo * by itself. Therefore, a completely different SWIG customization mechanism (%feature) is used for this purpose. Consult the Customization Features chapter for more information about that. Typemaps also can't be used to rearrange or transform the order of arguments. For example, if you had a function like this: 并且你想告诉 SWIG make_Foo(int n) 返回了一个新分配的对象（目的是提供更好的内存管理）。显然，make_Foo(int n) 的此属性不是本身将与数据类型 Foo * 相关联的属性。因此，为此目的要使用完全不同的 SWIG 定制机制（%feature）。有关更多信息，请参考自定义功能章节。 类型映射也不能用于重新排列或转换参数的顺序。例如，如果你具有如下函数： void foo(int, char *);  you can't use typemaps to interchange the arguments, allowing you to call the function like this: 你不能使用类型映射来交换参数，进而允许你能这样调用函数： foo("hello", 3) # Reversed arguments  If you want to change the calling conventions of a function, write a helper function instead. For example: 如果要更改函数的调用约定，请编写辅助函数。例如： %rename(foo) wrap_foo; %inline %{ void wrap_foo(char *s, int x) { foo(x, s); } %}  ### 11.1.7 与面向切面编程的相似之处 SWIG has parallels to Aspect Oriented Software Development (AOP). The AOP terminology with respect to SWIG typemaps can be viewed as follows: • Cross-cutting concerns: The cross-cutting concerns are the modularization of the functionality that the typemaps implement, which is primarily marshalling of types from/to the target language and C/C++. • Advice: The typemap body contains code which is executed whenever the marshalling is required. • Pointcut: The pointcuts are the positions in the wrapper code that the typemap code is generated into. • Aspect: Aspects are the combination of the pointcut and the advice, hence each typemap is an aspect. SWIG can also be viewed as has having a second set of aspects based around %feature. Features such as %exception are also cross-cutting concerns as they encapsulate code that can be used to add logging or exception handling to any function. SWIG 与面向切面的软件开发（AOP）相似。与 SWIG 类型映射有关的 AOP 术语如下： • 横切关注点：横切关注点是类型映射所实现功能的模块化，主要是将目标语言和 C/C++ 之间的类型进行编组。 • 通知：类型映射主体包含在需要编组时执行的代码。 • 切入点：切入点是包装器代码中生成类型映射代码的位置。 • 切面：切面是切入点和通知的组合，因此每个类型映射都是一个切面。 也可以将 SWIG 视为具有基于 %feature 的第二组切面。诸如 %exception 之类的功能也是横切关注点，因为它们封装了可用于向任何函数添加日志记录或异常处理的代码。 ### 11.1.8 本章的剩余部分 The rest of this chapter provides detailed information for people who want to write new typemaps. This information is of particular importance to anyone who intends to write a new SWIG target language module. Power users can also use this information to write application specific type conversion rules. Since typemaps are strongly tied to the underlying C++ type system, subsequent sections assume that you are reasonably familiar with the basic details of values, pointers, references, arrays, type qualifiers (e.g., const), structures, namespaces, templates, and memory management in C/C++. If not, you would be well-advised to consult a copy of "The C Programming Language" by Kernighan and Ritchie or "The C++ Programming Language" by Stroustrup before going any further. 本章的剩余部分为想要编写新的类型映射的人提供了详细的信息。对于打算为 SWIG 编写新目标语言模块的人来说，这些信息都特别重要。高级用户还可以使用这些信息来编写应用程序特定的类型转换规则。 由于类型映射与底层 C++ 类型系统紧密相关，因此后续章节假定你对值、指针、引用、数组、类型限定符（例如 const）、结构体、命名空间、模板和 C/C++ 中的内存管理相当熟悉。如果不是这样，建议你先阅读 Kernighan 和 Ritchie 撰写的《The C Programming Language》或 Stroustrup 撰写的《The C++ Programming Language》。 ## 11.2 类型映射详述 This section describes the behavior of the %typemap directive itself. 本节描述了 %typemap 指令本身的行为。 ### 11.2.1 定义一个类型映射 New typemaps are defined using the %typemap declaration. The general form of this declaration is as follows (parts enclosed in [...] are optional): 新的类型映射使用 %typemap 声明定义。该声明的一般形式如下（[...] 中的部分是可选的）： %typemap(method [, modifiers]) typelist code ;  method is a simply a name that specifies what kind of typemap is being defined. It is usually a name like "in", "out", or "argout". The purpose of these methods is described later. modifiers is an optional comma separated list of name="value" values. These are sometimes to attach extra information to a typemap and is often target-language dependent. They are also known as typemap attributes. typelist is a list of the C++ type patterns that the typemap will match. The general form of this list is as follows: method 是一个简单的名称，用于指定要定义的类型映射。通常，它的名称类似于 inoutargout。这些方法的目的将在后面说明。 modifiers 是一个可选的逗号分隔列表，其中包含 name="value" 值。这些有时会在类型映射上附加额外的信息，并且通常取决于目标语言。它们也称为类型映射属性。 typelist 是类型映射将匹配的 C++ 类型模式的列表。此列表的一般形式如下： typelist : typepattern [, typepattern, typepattern, ... ] ; typepattern : type [ (parms) ] | type name [ (parms) ] | ( typelist ) [ (parms) ]  Each type pattern is either a simple type, a simple type and argument name, or a list of types in the case of multi-argument typemaps. In addition, each type pattern can be parameterized with a list of temporary variables (parms). The purpose of these variables will be explained shortly. code specifies the code used in the typemap. Usually this is C/C++ code, but in the statically typed target languages, such as Java and C#, this can contain target language code for certain typemaps. It can take any one of the following forms: 每个类型模式可以是简单类型、简单类型和参数名称，或者在多参数类型映射下的类型列表。此外，可以使用一系列临时变量（参数）对每个类型模式进行参数化。这些变量的目的将在稍后说明。 code 指定类型映射中使用的代码。通常这是 C/C++ 代码，但是在静态类型的目标语言（例如 Java 和 C#）中，它可以包含某些类型映射的目标语言代码。可以采用以下任何一种形式： code : { ... } | " ... " | %{ ... %}  Note that the preprocessor will expand code within the {} delimiters, but not in the last two styles of delimiters, see Preprocessor and Typemaps. Here are some examples of valid typemap specifications: 请注意，预处理器将在 {} 分隔符内扩展代码，但不会在最后两种分隔符样式中扩展代码，请参阅《预处理器与类型映射》章节。以下是有效类型映射规范的一些示例： /* Simple typemap declarations */ %typemap(in) int {$1 = PyInt_AsLong($input); } %typemap(in) int "$1 = PyInt_AsLong($input);"; %typemap(in) int %{$1 = PyInt_AsLong($input); %} /* Typemap with extra argument name */ %typemap(in) int nonnegative { ... } /* Multiple types in one typemap */ %typemap(in) int, short, long {$1 = SvIV($input); } /* Typemap with modifiers */ %typemap(in, doc="integer") int "$1 = scm_to_int($input);"; /* Typemap applied to patterns of multiple arguments */ %typemap(in) (char *str, int len), (char *buffer, int size) {$1 = PyString_AsString($input);$2 = PyString_Size($input); } /* Typemap with extra pattern parameters */ %typemap(in, numinputs=0) int *output (int temp), long *output (long temp) {$1 = &temp;
}


Admittedly, it's not the most readable syntax at first glance. However, the purpose of the individual pieces will become clear.

### 11.2.2 类型映射作用范围

Once defined, a typemap remains in effect for all of the declarations that follow. A typemap may be redefined for different sections of an input file. For example:

// typemap1
%typemap(in) int {
...
}

int fact(int);                    // typemap1
int gcd(int x, int y);            // typemap1

// typemap2
%typemap(in) int {
...
}

int isprime(int);                 // typemap2


One exception to the typemap scoping rules pertains to the %extend declaration. %extend is used to attach new declarations to a class or structure definition. Because of this, all of the declarations in an %extend block are subject to the typemap rules that are in effect at the point where the class itself is defined. For example:

class Foo {
...
};

%typemap(in) int {
...
}

%extend Foo {
int blah(int x);    // typemap has no effect.  Declaration is attached to Foo which
// appears before the %typemap declaration.
};


### 11.2.3 复制类型映射

A typemap is copied by using assignment. For example:

%typemap(in) Integer = int;


or this:

%typemap(in) Integer, Number, int32_t = int;


Types are often managed by a collection of different typemaps. For example:

%typemap(in)     int { ... }
%typemap(out)    int { ... }
%typemap(varin)  int { ... }
%typemap(varout) int { ... }


To copy all of these typemaps to a new type, use %apply. For example:

%apply int { Integer };            // Copy all int typemaps to Integer
%apply int { Integer, Number };    // Copy all int typemaps to both Integer and Number


The patterns for %apply follow the same rules as for %typemap. For example:

%apply 的模式遵循与 %typemap 相同的规则。例如：

%apply int *output { Integer *output };                    // Typemap with name
%apply (char *buf, int len) { (char *buffer, int size) };  // Multiple arguments


### 11.2.4 删除类型映射

A typemap can be deleted by simply defining no code. For example:

%typemap(in) int;               // Clears typemap for int
%typemap(in) int, long, short;  // Clears typemap for int, long, short
%typemap(in) int *output;


The %clear directive clears all typemaps for a given type. For example:

%clear 指令清除给定类型的所有类型映射。例如：

%clear int;                     // Removes all types for int
%clear int *output, long *output;


Note: Since SWIG's default behavior is defined by typemaps, clearing a fundamental type like int will make that type unusable unless you also define a new set of typemaps immediately after the clear operation.

### 11.2.5 类型映射的位置

Typemap declarations can be declared in the global scope, within a C++ namespace, and within a C++ class. For example:

%typemap(in) int {
...
}

namespace std {
class string;
%typemap(in) string {
...
}
}

class Bar {
public:
typedef const int & const_reference;
%typemap(out) const_reference {
...
}
};


When a typemap appears inside a namespace or class, it stays in effect until the end of the SWIG input (just like before). However, the typemap takes the local scope into account. Therefore, this code

namespace std {
class string;
%typemap(in) string {
...
}
}


is really defining a typemap for the type std::string. You could have code like this:

namespace std {
class string;
%typemap(in) string {          /* std::string */
...
}
}

namespace Foo {
class string;
%typemap(in) string {          /* Foo::string */
...
}
}


In this case, there are two completely distinct typemaps that apply to two completely different types (std::string and Foo::string).

It should be noted that for scoping to work, SWIG has to know that string is a typename defined within a particular namespace. In this example, this is done using the forward class declaration class string.

## 11.3 模式匹配规则

The section describes the pattern matching rules by which C/C++ datatypes are associated with typemaps. The matching rules can be observed in practice by using the debugging options also described.

### 11.3.1 基本匹配规则

Typemaps are matched using both a type and a name (typically the name of a argument). For a given TYPE NAME pair, the following rules are applied, in order, to find a match. The first typemap found is used.

• Typemaps that exactly match TYPE and NAME.
• Typemaps that exactly match TYPE only.
• If TYPE is a C++ template of type T<TPARMS>, where TPARMS are the template parameters, the type is stripped of the template parameters and the following checks are then made:
• Typemaps that exactly match T and NAME.
• Typemaps that exactly match T only.

If TYPE includes qualifiers (const, volatile, etc.), each qualifier is stripped one at a time to form a new stripped type and the matching rules above are repeated on the stripped type. The left-most qualifier is stripped first, resulting in the right-most (or top-level) qualifier being stripped last. For example int const*const is first stripped to int *const then int *.

If TYPE is an array. The following transformation is made:

• Replace all dimensions to [ANY] and look for a generic array typemap.

To illustrate, suppose that you had a function like this:

• TYPENAME 完全匹配的类型映射。
• 仅与 TYPE 完全匹配的类型映射。
• 如果 TYPET<TPARMS> 类型的 C++ 模板，其中 TPARMS 是模板参数，则将类型的模板参数剥离，然后进行以下检查：
• TNAME 完全匹配的类型映射。
• 仅与 T 完全匹配的类型映射。

• 将所有维度替换为 [ANY]，并查找通用数组类型映射

int foo(const char *s);


To find a typemap for the argument const char *s, SWIG will search for the following typemaps:

const char *s           Exact type and name match
const char *            Exact type match
char *s                 Type and name match (qualifier stripped)
char *                  Type match (qualifier stripped)


When more than one typemap rule might be defined, only the first match found is actually used. Here is an example that shows how some of the basic rules are applied:

%typemap(in) int *x {
... typemap 1
}

%typemap(in) int * {
... typemap 2
}

%typemap(in) const int *z {
... typemap 3
}

%typemap(in) int [4] {
... typemap 4
}

%typemap(in) int [ANY] {
... typemap 5
}

void A(int *x);        // int *x rule       (typemap 1)
void B(int *y);        // int * rule        (typemap 2)
void C(const int *x);  // int *x rule       (typemap 1)
void D(const int *z);  // const int *z rule (typemap 3)
void E(int x[4]);      // int [4] rule      (typemap 4)
void F(int x[1000]);   // int [ANY] rule    (typemap 5)


Compatibility note: SWIG-2.0.0 introduced stripping the qualifiers one step at a time. Prior versions stripped all qualifiers in one step.

### 11.3.2 typedef 还原匹配

If no match is found using the rules in the previous section, SWIG applies a typedef reduction to the type and repeats the typemap search for the reduced type. To illustrate, suppose you had code like this:

%typemap(in) int {
... typemap 1
}

typedef int Integer;
void blah(Integer x);


To find the typemap for Integer x, SWIG will first search for the following typemaps:

Integer x
Integer


Finding no match, it then applies a reduction Integer -> int to the type and repeats the search.

int x
int      --> match: typemap 1


Even though two types might be the same via typedef, SWIG allows typemaps to be defined for each typename independently. This allows for interesting customization possibilities based solely on the typename itself. For example, you could write code like this:

typedef double  pdouble;     // Positive double

// typemap 1
%typemap(in) double {
... get a double ...
}
// typemap 2
%typemap(in) pdouble {
... get a positive double ...
}
double sin(double x);           // typemap 1
pdouble sqrt(pdouble x);        // typemap 2


When reducing the type, only one typedef reduction is applied at a time. The search process continues to apply reductions until a match is found or until no more reductions can be made.

For complicated types, the reduction process can generate a long list of patterns. Consider the following:

typedef int Integer;
typedef Integer Row4[4];
void foo(Row4 rows[10]);


To find a match for the Row4 rows[10] argument, SWIG would check the following patterns, stopping only when it found a match:

Row4 rows[10]
Row4 [10]
Row4 rows[ANY]
Row4 [ANY]

# Reduce Row4 --> Integer[4]
Integer rows[10][4]
Integer [10][4]
Integer rows[ANY][ANY]
Integer [ANY][ANY]

# Reduce Integer --> int
int rows[10][4]
int [10][4]
int rows[ANY][ANY]
int [ANY][ANY]


For parameterized types like templates, the situation is even more complicated. Suppose you had some declarations like this:

typedef int Integer;
typedef foo<Integer, Integer> fooii;
void blah(fooii *x);


In this case, the following typemap patterns are searched for the argument fooii *x:

fooii *x
fooii *

# Reduce fooii --> foo<Integer, Integer>
foo<Integer, Integer> *x
foo<Integer, Integer> *

# Reduce Integer -> int
foo<int, Integer> *x
foo<int, Integer> *

# Reduce Integer -> int
foo<int, int> *x
foo<int, int> *


Typemap reductions are always applied to the left-most type that appears. Only when no reductions can be made to the left-most type are reductions made to other parts of the type. This behavior means that you could define a typemap for foo<int, Integer>, but a typemap for foo<Integer, int> would never be matched. Admittedly, this is rather esoteric--there's little practical reason to write a typemap quite like that. Of course, you could rely on this to confuse your coworkers even more.

As a point of clarification, it is worth emphasizing that typedef matching is a typedef reduction process only, that is, SWIG does not search for every single possible typedef. Given a type in a declaration, it will only reduce the type, it won't build it up looking for typedefs. For example, given the type Struct, the typemap below will not be used for the aStruct parameter, because Struct is fully reduced:

struct Struct {...};
typedef Struct StructTypedef;

%typemap(in) StructTypedef {
...
}

void go(Struct aStruct);


### 11.3.3 默认类型映射匹配规则

If the basic pattern matching rules result in no match being made, even after typedef reductions, the default typemap matching rules are used to look for a suitable typemap match. These rules match a generic typemap based on the reserved SWIGTYPE base type. For example pointers will use SWIGTYPE *and references will use SWIGTYPE &. More precisely, the rules are based on the C++ class template partial specialization matching rules used by C++ compilers when looking for an appropriate partial template specialization. This means that a match is chosen from the most specialized set of generic typemap types available. For example, when looking for a match to int const *, the rules will prefer to match SWIGTYPE const * if available before matching SWIGTYPE *, before matching SWIGTYPE.

Most SWIG language modules use typemaps to define the default behavior of the C primitive types. This is entirely straightforward. For example, a set of typemaps for primitives marshalled by value or const reference are written like this:

%typemap(in) int           "... convert to int ...";
%typemap(in) short         "... convert to short ...";
%typemap(in) float         "... convert to float ...";
...
%typemap(in) const int &   "... convert ...";
%typemap(in) const short & "... convert ...";
%typemap(in) const float & "... convert ...";
...


Since typemap matching follows all typedef declarations, any sort of type that is mapped to a primitive type by value or const reference through typedef will be picked up by one of these primitive typemaps. Most language modules also define typemaps for char pointers and char arrays to handle strings, so these non-default types will also be used in preference as the basic typemap matching rules provide a better match than the default typemap matching rules.

Below is a list of the typical default types supplied by language modules, showing what the "in" typemap would look like:

%typemap(in) SWIGTYPE &            { ... default reference handling ...                       };
%typemap(in) SWIGTYPE *            { ... default pointer handling ...                         };
%typemap(in) SWIGTYPE *const       { ... default pointer const handling ...                   };
%typemap(in) SWIGTYPE *const&      { ... default pointer const reference handling ...         };
%typemap(in) SWIGTYPE[ANY]         { ... 1D fixed size arrays handlling ...                   };
%typemap(in) SWIGTYPE []           { ... unknown sized array handling ...                     };
%typemap(in) enum SWIGTYPE         { ... default handling for enum values ...                 };
%typemap(in) const enum SWIGTYPE & { ... default handling for const enum reference values ... };
%typemap(in) SWIGTYPE (CLASS::*)   { ... default pointer member handling ...                  };
%typemap(in) SWIGTYPE              { ... simple default handling ...                          };


If you wanted to change SWIG's default handling for simple pointers, you would simply redefine the rule for SWIGTYPE *. Note, the simple default typemap rule is used to match against simple types that don't match any other rules:

%typemap(in) SWIGTYPE              { ... simple default handling ...                          }


This typemap is important because it is the rule that gets triggered when call or return by value is used. For instance, if you have a declaration like this:

double dot_product(Vector a, Vector b);


The Vector type will usually just get matched against SWIGTYPE. The default implementation of SWIGTYPEis to convert the value into pointers (as described in this earlier section).

By redefining SWIGTYPE it may be possible to implement other behavior. For example, if you cleared all typemaps for SWIGTYPE, SWIG simply won't wrap any unknown datatype (which might be useful for debugging). Alternatively, you might modify SWIGTYPE to marshal objects into strings instead of converting them to pointers.

Let's consider an example where the following typemaps are defined and SWIG is looking for the best match for the enum shown below:

Vector 类型通常只会与 SWIGTYPE 相匹配。SWIGTYPE 的默认实现是将值转换为指针（如本之前的章节所述）。

%typemap(in) const Hello &          { ... }
%typemap(in) const enum SWIGTYPE &  { ... }
%typemap(in) enum SWIGTYPE &        { ... }
%typemap(in) SWIGTYPE &             { ... }
%typemap(in) SWIGTYPE               { ... }

enum Hello {};
const Hello &hi;


The typemap at the top of the list will be chosen, not because it is defined first, but because it is the closest match for the type being wrapped. If any of the typemaps in the above list were not defined, then the next one on the list would have precedence.

The best way to explore the default typemaps is to look at the ones already defined for a particular language module. Typemap definitions are usually found in the SWIG library in a file such as java.swg, csharp.swg etc. However, for many of the target languages the typemaps are hidden behind complicated macros, so the best way to view the default typemaps, or any typemaps for that matter, is to look at the preprocessed output by running swig -E on any interface file. Finally the best way to view the typemap matching rules in action is via the debugging typemap pattern matching options covered later on.

Compatibility note: The default typemap matching rules were modified in SWIG-2.0.0 from a slightly simpler scheme to match the current C++ class template partial specialization matching rules.

### 11.3.4 多参数类型映射

When multi-argument typemaps are specified, they take precedence over any typemaps specified for a single type. For example:

%typemap(in) (char *buffer, int len) {
// typemap 1
}

%typemap(in) char *buffer {
// typemap 2
}

void foo(char *buffer, int len, int count); // (char *buffer, int len)
void bar(char *buffer, int blah);           // char *buffer


Multi-argument typemaps are also more restrictive in the way that they are matched. Currently, the first argument follows the matching rules described in the previous section, but all subsequent arguments must match exactly.

### 11.3.5 匹配规则对比 C++ 模板

For those intimately familiar with C++ templates, a comparison of the typemap matching rules and template type deduction is interesting. The two areas considered are firstly the default typemaps and their similarities to partial template specialization and secondly, non-default typemaps and their similarities to full template specialization.

For default (SWIGTYPE) typemaps the rules are inspired by C++ class template partial specialization. For example, given partial specialization for T const& :

template <typename T> struct X             { void a(); };
template <typename T> struct X< T const& > { void b(); };


The full (unspecialized) template is matched with most types, such as:

X< int & >            x1;  x1.a();


and the following all match the T const& partial specialization:

X< int *const& >      x2;  x2.b();
X< int const*const& > x3;  x3.b();
X< int const& >       x4;  x4.b();


Now, given just these two default typemaps, where T is analogous to SWIGTYPE:

%typemap(...) SWIGTYPE        { ... }
%typemap(...) SWIGTYPE const& { ... }


The generic default typemap SWIGTYPE is used with most types, such as

int &


and the following all match the SWIGTYPE const& typemap, just like the partial template matching:

int *const&
int const*const&
int const&


Note that the template and typemap matching rules are not identical for all default typemaps though, for example, with arrays.

For non-default typemaps, one might expect SWIG to follow the fully specialized template rules. This is nearly the case, but not quite. Consider a very similar example to the earlier partially specialized template but this time there is a fully specialized template:

template <typename T> struct Y       { void a(); };
template <> struct Y< int const & >  { void b(); };


Only the one type matches the specialized template exactly:

Y< int & >             y1;  y1.a();
Y< int *const& >       y2;  y2.a();
Y< int const *const& > y3;  y3.a();
Y< int const& >        y4;  y4.b(); // fully specialized match


Given typemaps with the same types used for the template declared above, where T is again analogous to SWIGTYPE:

%typemap(...) SWIGTYPE        { ... }
%typemap(...) int const&      { ... }


The comparison between non-default typemaps and fully specialized single parameter templates turns out to be the same, as just the one type will match the non-default typemap:

int &
int *const&
int const*const&
int const&        // matches non-default typemap int const&


However, if a non-const type is used instead:

%typemap(...) SWIGTYPE        { ... }
%typemap(...) int &           { ... }


then there is a clear difference to template matching as both the const and non-const types match the typemap:

int &             // matches non-default typemap int &
int *const&
int const*const&
int const&        // matches non-default typemap int &


There are other subtle differences such as typedef handling, but at least it should be clear that the typemap matching rules are similar to those for specialized template handling.

### 11.3.6 调试类型映射模式匹配

There are two useful debug command line options available for debugging typemaps, -debug-tmsearchand -debug-tmused.

The -debug-tmsearch option is a verbose option for debugging typemap searches. This can be very useful for watching the pattern matching process in action and for debugging which typemaps are used. The option displays all the typemaps and types that are looked for until a successful pattern match is made. As the display includes searches for each and every type needed for wrapping, the amount of information displayed can be large. Normally you would manually search through the displayed information for the particular type that you are interested in.

For example, consider some of the code used in the Typedef reductions section already covered:

-debug-tmsearch 选项是用于调试类型映射搜索的详细选项。这对于观察实际的模式匹配过程，以及调试使用哪种类型映射非常有用。该选项显示在成功进行模式匹配之前要查找的所有类型映射和类型。由于显示内容包括对包装所需的每种类型的搜索，因此显示的信息量可能很大。通常，你将在显示的信息中手动搜索感兴趣的特定类型。

typedef int Integer;
typedef Integer Row4[4];
void foo(Row4 rows[10]);


A sample of the debugging output is shown below for the "in" typemap:

swig -perl -debug-tmsearch example.i
...
example.h:3: Searching for a suitable 'in' typemap for: Row4 rows[10]
Looking for: Row4 rows[10]
Looking for: Row4 [10]
Looking for: Row4 rows[ANY]
Looking for: Row4 [ANY]
Looking for: Integer rows[10][4]
Looking for: Integer [10][4]
Looking for: Integer rows[ANY][ANY]
Looking for: Integer [ANY][ANY]
Looking for: int rows[10][4]
Looking for: int [10][4]
Looking for: int rows[ANY][ANY]
Looking for: int [ANY][ANY]
Looking for: SWIGTYPE rows[ANY][ANY]
Looking for: SWIGTYPE [ANY][ANY]
Looking for: SWIGTYPE rows[ANY][]
Looking for: SWIGTYPE [ANY][]
Looking for: SWIGTYPE *rows[ANY]
Looking for: SWIGTYPE *[ANY]
Looking for: SWIGTYPE rows[ANY]
Looking for: SWIGTYPE [ANY]
Looking for: SWIGTYPE rows[]
Looking for: SWIGTYPE []
Using: %typemap(in) SWIGTYPE []
...


showing that the best default match supplied by SWIG is the SWIGTYPE [] typemap. As the example shows, the successful match displays the used typemap source including typemap method, type and optional name in one of these simplified formats:

• Using: %typemap(method) type name
• Using: %typemap(method) type name = type2 name2
• Using: %apply type2 name2 { type name }

This information might meet your debugging needs, however, you might want to analyze further. If you next invoke SWIG with the -E option to display the preprocessed output, and search for the particular typemap used, you'll find the full typemap contents (example shown below for Python):

• Using: %typemap(method) type name
• Using: %typemap(method) type name = type2 name2
• Using: %apply type2 name2 { type name }

%typemap(in, noblock=1) SWIGTYPE [] (void *argp = 0, int res = 0) {
res = SWIG_ConvertPtr($input, &argp,$descriptor, $disown | 0 ); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method '" "$symname" "', argument "
"$argnum"" of type '" "$type""'");
}
$1 = ($ltype)(argp);
}


The generated code for the foo wrapper will then contain the snippets of the typemap with the special variables expanded. The rest of this chapter will need reading though to fully understand all of this, however, the relevant parts of the generated code for the above typemap can be seen below:

SWIGINTERN PyObject *_wrap_foo(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
...
void *argp1 = 0 ;
int res1 = 0 ;
...
res1 = SWIG_ConvertPtr(obj0, &argp1, SWIGTYPE_p_a_4__int, 0 |  0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "foo" "', argument "
"1"" of type '" "int [10][4]""'");
}
arg1 = (int (*)[4])(argp1);
...
}


Searches for multi-argument typemaps are not mentioned unless a matching multi-argument typemap does actually exist. For example, the output for the code in the earlier multi-arguments section is as follows:

...
example.h:39: Searching for a suitable 'in' typemap for: char *buffer
Looking for: char *buffer
Multi-argument typemap found...
Using: %typemap(in) (char *buffer, int len)
...


The second option for debugging is -debug-tmused and this displays the typemaps used. This option is a less verbose version of the -debug-tmsearch option as it only displays each successfully found typemap on a separate single line. The output displays the type, and name if present, the typemap method in brackets and then the actual typemap used in the same simplified format output by the -debug-tmsearchoption. Below is the output for the example code at the start of this section on debugging.

$swig -perl -debug-tmused example.i example.h:3: Typemap for Row4 rows[10] (in) : %typemap(in) SWIGTYPE [] example.h:3: Typemap for Row4 rows[10] (typecheck) : %typemap(typecheck) SWIGTYPE * example.h:3: Typemap for Row4 rows[10] (freearg) : %typemap(freearg) SWIGTYPE [] example.h:3: Typemap for void foo (out) : %typemap(out) void  Now, consider the following interface file: 现在，考虑下面的接口文件： %module example %{ void set_value(const char* val) {} %} %typemap(check) char *NON_NULL { if (!$1) {
/* ... error handling ... */
}
}

// use default pointer handling instead of strings
%apply SWIGTYPE * { const char* val, const char* another_value }

%typemap(check) const char* val = char* NON_NULL;

%typemap(arginit, noblock=1) const char* val {
$1 = ""; } void set_value(const char* val);  and the output debug: 输出调试结果： swig -perl5 -debug-tmused example.i example.i:21: Typemap for char const *val (arginit) : %typemap(arginit) char const *val example.i:21: Typemap for char const *val (in) : %apply SWIGTYPE * { char const *val } example.i:21: Typemap for char const *val (typecheck) : %apply SWIGTYPE * { char const *val } example.i:21: Typemap for char const *val (check) : %typemap(check) char const *val = char *NON_NULL example.i:21: Typemap for char const *val (freearg) : %apply SWIGTYPE * { char const *val } example.i:21: Typemap for void set_value (out) : %typemap(out) void  The following observations about what is displayed can be noted (the same applies for -debug-tmsearch): • The relevant typemap is shown, but for typemap copying, the appropriate %typemap or %apply is displayed, for example, the "check" and "in" typemaps. • The typemap modifiers are not shown, eg the noblock=1 modifier in the "arginit" typemap. • The exact %apply statement might look different to what is in the actual code. For example, the const char* another_value is not shown as it is not relevant here. Also the types may be displayed slightly differently - char const * and not const char*. 可以注意到以下有关显示内容的观察结果（-debug-tmsearch 同样适用）： • 显示了相关的类型映射，但是对于复制类型映射，将显示适当的 %typemap%apply，例如，checkin 类型映射。 • 类型映射修饰符未显示，例如，arginit 类型映射中的 noblock = 1 修饰符。 • 确切的 %apply 语句可能看起来与实际代码不同。例如，未显示 const char* another_value，因为此处不相关。同样，类型的显示可能略有不同——char const* 而不是 const char* ## 11.4 代码生成规则 This section describes rules by which typemap code is inserted into the generated wrapper code. 本节描述将类型映射代码插入到生成的包装器代码中的规则。 ### 11.4.1 作用域 When a typemap is defined like this: 当类型映射定义如下： %typemap(in) int {$1 = PyInt_AsLong($input); }  the typemap code is inserted into the wrapper function using a new block scope. In other words, the wrapper code will look like this: 使用新的块作用域将类型映射代码插入包装器函数。换句话说，包装器代码将如下所示： wrap_whatever() { ... // Typemap code { arg1 = PyInt_AsLong(obj1); } ... }  Because the typemap code is enclosed in its own block, it is legal to declare temporary variables for use during typemap execution. For example: 因为类型映射代码包含在其自己的块中，所以声明临时变量供在类型映射执行期间使用是合法的。例如： %typemap(in) short { long temp; /* Temporary value */ if (Tcl_GetLongFromObj(interp,$input, &temp) != TCL_OK) {
return TCL_ERROR;
}
$1 = (short) temp; }  Of course, any variables that you declare inside a typemap are destroyed as soon as the typemap code has executed (they are not visible to other parts of the wrapper function or other typemaps that might use the same variable names). Occasionally, typemap code will be specified using a few alternative forms. For example: 当然，你在类型映射中声明的任何变量都将在该类型映射代码执行后立即销毁（它们对于包装器函数的其他部分，或其他可能使用相同变量名的类型映射不可见）。 有时，会使用一些其他形式来指定类型映射代码。例如： %typemap(in) int "$1 = PyInt_AsLong($input);"; %typemap(in) int %{$1 = PyInt_AsLong($input); %} %typemap(in, noblock=1) int {$1 = PyInt_AsLong($input); }  These three forms are mainly used for cosmetics--the specified code is not enclosed inside a block scope when it is emitted. This sometimes results in a less complicated looking wrapper function. Note that only the third of the three typemaps have the typemap code passed through the SWIG preprocessor. 这三种形式主要用于化妆——发出特定代码时，指定代码未包含在块作用域内。有时这会导致看起来不太复杂的包装器函数。请注意，三个类型映射中只有三分之一具有通过 SWIG 预处理程序传递的类型映射代码。 ### 11.4.2 声明新的局部变量 Sometimes it is useful to declare a new local variable that exists within the scope of the entire wrapper function. A good example of this might be an application in which you wanted to marshal strings. Suppose you had a C++ function like this 有时，声明存在于整个包装器函数范围内的新局部变量很有用。一个很好的例子就是你想在其中传递字符串的应用程序。假设你有一个这样的 C++ 函数 int foo(std::string *s);  and you wanted to pass a native string in the target language as an argument. For instance, in Perl, you wanted the function to work like this: 并且你想传递目标语言中的原生字符串作为参数。例如，在 Perl 中，你希望函数像这样工作： $x = foo("Hello World");


To do this, you can't just pass a raw Perl string as the std::string * argument. Instead, you have to create a temporary std::string object, copy the Perl string data into it, and then pass a pointer to the object. To do this, simply specify the typemap with an extra parameter like this:

%typemap(in) std::string * (std::string temp) {
unsigned int len;
char        *s;
s = SvPV($input, len); /* Extract string data */ temp.assign(s, len); /* Assign to temp */$1 = &temp;                   /* Set argument to point to temp */
}


In this case, temp becomes a local variable in the scope of the entire wrapper function. For example:

wrap_foo() {
std::string temp;   // <--- Declaration of temp goes here
...

/* Typemap code */
{
...
temp.assign(s, len);
...
}
...
}


When you set temp to a value, it persists for the duration of the wrapper function and gets cleaned up automatically on exit.

It is perfectly safe to use more than one typemap involving local variables in the same declaration. For example, you could declare a function as :

void foo(std::string *x, std::string *y, std::string *z);


This is safely handled because SWIG actually renames all local variable references by appending an argument number suffix. Therefore, the generated code would actually look like this:

wrap_foo() {
int *arg1;    /* Actual arguments */
int *arg2;
int *arg3;
std::string temp1;    /* Locals declared in the typemap */
std::string temp2;
std::string temp3;
...
{
char *s;
unsigned int len;
...
temp1.assign(s, len);
arg1 = *temp1;
}
{
char *s;
unsigned int len;
...
temp2.assign(s, len);
arg2 = &temp2;
}
{
char *s;
unsigned int len;
...
temp3.assign(s, len);
arg3 = &temp3;
}
...
}


There is an exception: if the variable name starts with the _global_ prefix, the argument number is not appended. Such variables can be used throughout the generated wrapper function. For example, the above typemap could be rewritten to use _global_temp instead of temp and the generated code would then contain a single _global_temp variable instead of temp1, temp2 and temp3:

%typemap(in) std::string * (std::string _global_temp) {
... as above ...
}


Some typemaps do not recognize local variables (or they may simply not apply). At this time, only typemaps that apply to argument conversion support this (input typemaps such as the "in" typemap).

Note:

When declaring a typemap for multiple types, each type must have its own local variable declaration.

%typemap(in) const std::string *, std::string * (std::string temp) // NO!
// only std::string * has a local variable
// const std::string * does not (oops)
....

%typemap(in) const std::string * (std::string temp), std::string * (std::string temp) // Correct
....


### 11.4.3 特殊变量

Within all typemaps, the following special variables are expanded. This is by no means a complete list as some target languages have additional special variables which are documented in the language specific chapters.

Variable Meaning
$n A C local variable corresponding to type n in the typemap pattern. $argnum Argument number. Only available in typemaps related to argument conversion
$n_name Argument name $n_type Real C datatype of type n.
$n_ltype ltype of type n $n_mangle Mangled form of type n. For example _p_Foo
$n_descriptor Type descriptor structure for type n. For exampleSWIGTYPE_p_Foo. This is primarily used when interacting with the run-time type checker (described later). $*n_type Real C datatype of type n with one pointer removed.
$*n_ltype ltype of type n with one pointer removed. $*n_mangle Mangled form of type n with one pointer removed.
$*n_descriptor Type descriptor structure for type n with one pointer removed. $&n_type Real C datatype of type n with one pointer added.
$&n_ltype ltype of type n with one pointer added. $&n_mangle Mangled form of type n with one pointer added.
$&n_descriptor Type descriptor structure for type n with one pointer added. $n_basetype Base typename with all pointers and qualifiers stripped.

Within the table, $n refers to a specific type within the typemap specification. For example, if you write this 在表中，$n 表示类型映射规范中的特定类型。例如，如果你编写此

%typemap(in) int *INPUT {

}


then $1 refers to int *INPUT. If you have a typemap like this, 那么 $1 指向 int *INPUT。如果你有如下类型映射，

%typemap(in) (int argc, char *argv[]) {
...
}


then $1 refers to int argc and$2 refers to char *argv[].

Substitutions related to types and names always fill in values from the actual code that was matched. This is useful when a typemap might match multiple C datatype. For example:

%typemap(in)  int, short, long {
$1 = ($1_ltype) PyInt_AsLong($input); }  In this case, $1_ltype is replaced with the datatype that is actually matched.

When typemap code is emitted, the C/C++ datatype of the special variables $1 and $2 is always an "ltype." An "ltype" is simply a type that can legally appear on the left-hand side of a C assignment operation. Here are a few examples of types and ltypes:

temp = PyInt_AsLong($input);$1 = &temp;
}


There is one word of caution about declaring local variables in this manner. If you declare a local variable using a type substitution such as $1_ltype temp, it won't work like you expect for arrays and certain kinds of pointers. For example, if you wrote this, 以这种方式声明局部变量有一个警告。如果你使用诸如 $1_ltype temp 之类的类型替换声明局部变量，它将无法像你期望的那样使用数组和某些类型的指针。例如，如果你编写了此代码，

%typemap(in) int [10][20] {
$1_ltype temp; }  then the declaration of temp will be expanded as 那么 temp 的声明将被扩展为 int (*)[20] temp;  This is illegal C syntax and won't compile. There is currently no straightforward way to work around this problem in SWIG due to the way that typemap code is expanded and processed. However, one possible workaround is to simply pick an alternative type such as void * and use casts to get the correct type when needed. For example: 这是非法的 C 语法，不会被编译。由于类型映射代码的扩展和处理方式，当前在 SWIG 中没有解决此问题的简单方法。然而，一种可能的解决方法是简单地选择一种替代类型，例如 void *，并在需要时使用强制类型转换来获取正确的类型。例如： %typemap(in) int [10][20] { void *temp; ... (($1_ltype) temp)[i][j] = x;    /* set a value */
...
}


Another approach, which only works for arrays is to use the $1_basetype substitution. For example: 另一种只对数组有效的方法是使用 $1_basetype 替换。例如：

%typemap(in) int [10][20] {
$1_basetype temp[10][20]; ... temp[i][j] = x; /* set a value */ ... }  ### 11.4.4 特殊变量宏 Special variable macros are like macro functions in that they take one or more input arguments which are used for the macro expansion. They look like macro/function calls but use the special variable $ prefix to the macro name. Note that unlike normal macros, the expansion is not done by the preprocessor, it is done during the SWIG parsing/compilation stages. The following special variable macros are available across all language modules.

This macro expands into the type descriptor structure for any C/C++ type specified in type. It behaves like the $1_descriptor special variable described above except that the type to expand is taken from the macro argument rather than inferred from the typemap type. For example, $descriptor(std::vector<int> *) will expand into SWIGTYPE_p_std__vectorT_int_t. This macro is mostly used in the scripting target languages and is demonstrated later in the Run-time type checker usage section.

#### 11.4.4.2 $typemap(method, typepattern) This macro uses the pattern matching rules described earlier to lookup and then substitute the special variable macro with the code in the matched typemap. The typemap to search for is specified by the arguments, where method is the typemap method name and typepattern is a type pattern as per the %typemap specification in the Defining a typemap section. The special variables within the matched typemap are expanded into those for the matched typemap type, not the typemap within which the macro is called. In practice, there is little use for this macro in the scripting target languages. It is mostly used in the target languages that are statically typed as a way to obtain the target language type given the C/C++ type and more commonly only when the C++ type is a template parameter. The example below is for C# only and uses some typemap method names documented in the C# chapter, but it shows some of the possible syntax variations. 此宏使用前面描述的模式匹配规则查找，然后用匹配的类型映射中的代码替换特殊变量宏。根据参数指定要搜索的类型映射，其中 method 是类型映射方法名称，而 typepattern 是类型模式，正如定义类型映射章节的 %typemap 规则。 匹配的类型映射中的特殊变量将扩展为匹配的类型映射类型的特殊变量，而不是其中调用宏的类型映射。实际上，在脚本目标语言中，此宏很少使用。它通常用在目标语言中，这些目标语言是静态类型化的，以便在给定 C/C++ 类型的情况下获取目标语言类型，并且更常见的情况是仅在 C++ 类型是模板参数时使用。 下面的示例仅适用于 C#，并使用了 C# 一章中记录的某些类型映射方法名称，但它显示了一些可能的语法变体。 %typemap(cstype) unsigned long "uint" %typemap(cstype) unsigned long bb "bool" %typemap(cscode) BarClass %{ void foo($typemap(cstype, unsigned long aa) var1,
$typemap(cstype, unsigned long bb) var2,$typemap(cstype, (unsigned long bb)) var3,
$typemap(cstype, unsigned long) var4) { // do something } %}  The result is the following expansion 结果是下列扩展 %typemap(cstype) unsigned long "uint" %typemap(cstype) unsigned long bb "bool" %typemap(cscode) BarClass %{ void foo(uint var1, bool var2, bool var3, uint var4) { // do something } %}  ### 11.4.5 特殊变量与类型映射属性 As of SWIG-3.0.7 typemap attributes will also expand special variables and special variable macros. Example usage showing the expansion in the 'out' attribute (C# specific) as well as the main typemap body: 从 SWIG-3.0.7 开始，类型映射属性还将扩展特殊变量和特殊变量宏。 用法示例显示 out 属性（特定于 C#）以及主要的类型映射主体中的扩展： %typemap(ctype, out="$*1_ltype") unsigned int& "$*1_ltype"  is equivalent to the following as $*1_ltype expands to unsigned int:

$symname - Name of function/method being wrapped  This is probably the most commonly redefined typemap because it can be used to implement customized conversions. In addition, the "in" typemap allows the number of converted arguments to be specified. The numinputs attributes facilitates this. For example: 这可能是最常见的重新定义的类型映射，因为它可用于实现自定义转换。 另外，in 类型映射允许指定转换参数的数量。numinputs 属性有助于实现这一点。例如： // Ignored argument. %typemap(in, numinputs=0) int *out (int temp) {$1 = &temp;
}


At this time, only zero or one arguments may be converted. When numinputs is set to 0, the argument is effectively ignored and cannot be supplied from the target language. The argument is still required when making the C/C++ call and the above typemap shows the value used is instead obtained from a locally declared variable called temp. Usually numinputs is not specified, whereupon the default value is 1, that is, there is a one to one mapping of the number of arguments when used from the target language to the C/C++ call. Multi-argument typemaps provide a similar concept where the number of arguments mapped from the target language to C/C++ can be changed for multiple adjacent C/C++ arguments.

Compatibility note: Specifying numinputs=0 is the same as the old "ignore" typemap.

### 11.5.2 typecheck 类型映射

The "typecheck" typemap is used to support overloaded functions and methods. It merely checks an argument to see whether or not it matches a specific type. For example:

typecheck 类型映射用于支持重载的函数和方法。它仅检查参数以查看其是否与特定类型匹配。例如：

%typemap(typecheck, precedence=SWIG_TYPECHECK_INTEGER) int {
$1 = PyInt_Check($input) ? 1 : 0;
}


For typechecking, the $1 variable is always a simple integer that is set to 1 or 0 depending on whether or not the input argument is the correct type. Set to 1 if the input argument is the correct type otherwise set to 0. If you define new "in" typemaps and your program uses overloaded methods, you should also define a collection of "typecheck" typemaps. More details about this follow in the Typemaps and overloading section. 对于类型检查，$1 变量始终是一个简单整数，根据输入参数是否为正确的类型将其设置为 10。如果输入参数是正确的类型，则设置为 1，否则设置为 0

### 11.5.3 out 类型映射

The "out" typemap is used to convert function/method return values from C into the target language. For example:

out 类型映射用于将函数或方法的返回值从 C 转换为目标语言。例如：

%typemap(out) int {
$result = PyInt_FromLong($1);
}


The following special variables are available.

$result - Result object returned to target language.$symname          - Name of function/method being wrapped


The "out" typemap supports an optional attribute flag called "optimal". This is for code optimisation and is detailed in the Optimal code generation when returning by value section.

out 类型映射支持名为 optimal 的可选属性标志。这是用于代码优化的，在按值返回时的最佳代码生成章节中进行了详细说明。

### 11.5.4 arginit 类型映射

The "arginit" typemap is used to set the initial value of a function argument--before any conversion has occurred. This is not normally necessary, but might be useful in highly specialized applications. For example:

// Set argument to NULL before any conversion occurs
%typemap(arginit) int *data {
$1 = NULL; }  ### 11.5.5 default 类型映射 The "default" typemap is used to turn an argument into a default argument. For example: default 类型映射用于将参数转换为默认参数。例如： %typemap(default) int flags {$1 = DEFAULT_FLAGS;
}
...
int foo(int x, int y, int flags);


The primary use of this typemap is to either change the wrapping of default arguments or specify a default argument in a language where they aren't supported (like C). Target languages that do not support optional arguments, such as Java and C#, effectively ignore the value specified by this typemap as all arguments must be given.

Once a default typemap has been applied to an argument, all arguments that follow must have default values. See the Default/optional arguments section for further information on default argument wrapping.

### 11.5.6 check 类型映射

The "check" typemap is used to supply value checking code during argument conversion. The typemap is applied after arguments have been converted. For example:

check 类型映射用于在参数转换期间提供值检查代码。类型参数是在参数转换之后应用的。例如：

%typemap(check) int positive {
if ($1 <= 0) { SWIG_exception(SWIG_ValueError, "Expected positive value."); } }  ### 11.5.7 argout 类型映射 The "argout" typemap is used to return values from arguments. This is most commonly used to write wrappers for C/C++ functions that need to return multiple values. The "argout" typemap is almost always combined with an "in" typemap---possibly to ignore the input value. For example: argout 类型映射用于从参数返回值。这最常用于为需要返回多个值的 C/C++ 函数编写包装器。argout 类型映射几乎总是与 in 类型映射结合使用——可能会忽略输入值。例如： /* Set the input argument to point to a temporary variable */ %typemap(in, numinputs=0) int *out (int temp) {$1 = &temp;
}

%typemap(argout) int *out {
// Append output value $1 to$result
...
}


The following special variables are available.

$result - Result object returned to target language.$input            - The original input object passed.
$symname - Name of function/method being wrapped  The code supplied to the "argout" typemap is always placed after the "out" typemap. If multiple return values are used, the extra return values are often appended to return value of the function. See the typemaps.i library file for examples. 提供给 argout 类型映射的代码始终放置在 out 类型映射之后。如果使用多个返回值，则通常会将多余的返回值附加到函数的返回值上。 有关示例，请参见 typemaps.i 库文件。 ### 11.5.8 freearg 类型映射 The "freearg" typemap is used to cleanup argument data. It is only used when an argument might have allocated resources that need to be cleaned up when the wrapper function exits. The "freearg" typemap usually cleans up argument resources allocated by the "in" typemap. For example: freearg 类型映射用于清除参数数据。仅当参数可能分配了包装器函数退出时需要清除的资源时才使用它。通常，freearg 类型映射会清除 in 类型映射分配的参数资源。例如： // Get a list of integers %typemap(in) int *items { int nitems = Length($input);
$1 = (int *) malloc(sizeof(int)*nitems); } // Free the list %typemap(freearg) int *items { free($1);
}


The "freearg" typemap inserted at the end of the wrapper function, just before control is returned back to the target language. This code is also placed into a special variable $cleanup that may be used in other typemaps whenever a wrapper function needs to abort prematurely. 在控件返回到目标语言之前，将 freearg 类型映射插入包装器函数的末尾。这段代码也被放入一个特殊的变量 $cleanup 中，只要包装器函数需要提前中止，该变量就可以在其他类型映射中使用。

### 11.5.9 newfree 类型映射

The "newfree" typemap is used in conjunction with the %newobject directive and is used to deallocate memory used by the return result of a function. For example:

newfree 类型映射与 %newobject 指令一起使用，用于释放函数返回结果使用的内存。例如：

%typemap(newfree) string * {
delete $1; } %typemap(out) string * {$result = PyString_FromString($1->c_str()); } ... %newobject foo; ... string *foo();  See Object ownership and %newobject for further details. 更多细节请查看对象所有权和 %newobject章节。 ### 11.5.10 ret 类型映射 The "ret" typemap is not used very often, but can be useful for anything associated with the return type, such as resource management, return value error checking, etc. Usually this can all be done in the "out" typemap, but sometimes it is handy to use the "out" typemap code untouched and add to the generated code using the code in the "ret" typemap. One such case is memory clean up. For example, a stringheap_t type is defined indicating that the returned memory must be deleted and a string_t type is defined indicating that the returned memory must not be deleted. ret 类型映射不是很经常使用，但是对于与返回类型相关的任何事情（例如资源管理，返回值错误检查等）都很有用。通常都可以在 out 类型映射中完成，但是有时方便地使用未修改的 out 类型映射代码，并使用 ret 类型映射中的代码添加到生成的代码中。一种这样的情况是内存清理。例如，定义了 stringheap_t 类型，指示必须删除返回的内存，定义 string_t 类型，指示必须删除返回的内存。 %typemap(ret) stringheap_t %{ free($1);
%}

typedef char * string_t;
typedef char * stringheap_t;

string_t MakeString1();
stringheap_t MakeString2();


The "ret" typemap above will only be used for MakeString2, but both functions will use the default "out" typemap for char * provided by SWIG. The code above would ensure the appropriate memory is freed in all target languages as the need to provide custom "out" typemaps (which involve target language specific code) is not necessary.

This approach is an alternative to using the "newfree" typemap and %newobject as there is no need to list all the functions that require the memory cleanup, it is purely done on types.

### 11.5.11 memberin 类型映射

The "memberin" typemap is used to copy data from an already converted input value into a structure member. It is typically used to handle array members and other special cases. For example:

memberin 类型映射用于将数据从已经转换的输入值复制到结构体成员中。它通常用于处理数组成员和其他特殊情况。例如：

%typemap(memberin) int [4] {
memmove($1,$input, 4*sizeof(int));
}


It is rarely necessary to write "memberin" typemaps---SWIG already provides a default implementation for arrays, strings, and other objects.

### 11.5.12 varin 类型映射

The "varin" typemap is used to convert objects in the target language to C for the purposes of assigning to a C/C++ global variable. This is implementation specific.

varin 类型映射用于将目标语言中的对象转换为 C，以分配给 C/C++ 全局变量。这是特定于实现的。

### 11.5.13 varout 类型映射

The "varout" typemap is used to convert a C/C++ object to an object in the target language when reading a C/C++ global variable. This is implementation specific.

### 11.5.14 throws 类型映射

The "throws" typemap is only used when SWIG parses a C++ method with an exception specification or has the %catches feature attached to the method. It provides a default mechanism for handling C++ methods that have declared the exceptions they will throw. The purpose of this typemap is to convert a C++ exception into an error or exception in the target language. It is slightly different to the other typemaps as it is based around the exception type rather than the type of a parameter or variable. For example:

%typemap(throws) const char * %{
PyErr_SetString(PyExc_RuntimeError, $1); SWIG_fail; %} void bar() throw (const char *);  As can be seen from the generated code below, SWIG generates an exception handler with the catch block comprising the "throws" typemap content. 从下面的生成代码中可以看出，SWIG 生成带有 catch 块的异常处理程序，该 catch 块包含 throw 类型映射内容。 ... try { bar(); } catch(char const *_e) { PyErr_SetString(PyExc_RuntimeError, _e); SWIG_fail; } ...  Note that if your methods do not have an exception specification yet they do throw exceptions, SWIG cannot know how to deal with them. For a neat way to handle these, see the Exception handling with %exception section. 请注意，如果你的方法没有异常规范，但它们确实会引发异常，则 SWIG 无法知道如何处理它们。有关处理这些错误的巧妙方法，请参阅使用 %exception 处理异常章节。 ## 11.6 一些类型映射示例 This section contains a few examples. Consult language module documentation for more examples. 本节包含一些示例。有关更多示例，请查阅语言模块的文档。 ### 11.6.1 数组的类型映射 A common use of typemaps is to provide support for C arrays appearing both as arguments to functions and as structure members. For example, suppose you had a function like this: 类型映射的一种常见用法是为 C 数组提供支持，这些 C 数组既作为函数的参数出现，又作为结构体成员出现。 例如，假设你具有如下函数： void set_vector(int type, float value[4]);  If you wanted to handle float value[4] as a list of floats, you might write a typemap similar to this: 如果你想将 float value[4] 作为一列浮点数表处理，则可以编写类似于以下内容的类型映射： %typemap(in) float value[4] (float temp[4]) { int i; if (!PySequence_Check($input)) {
PyErr_SetString(PyExc_ValueError, "Expected a sequence");
SWIG_fail;
}
if (PySequence_Length($input) != 4) { PyErr_SetString(PyExc_ValueError, "Size mismatch. Expected 4 elements"); SWIG_fail; } for (i = 0; i < 4; i++) { PyObject *o = PySequence_GetItem($input, i);
if (PyNumber_Check(o)) {
temp[i] = (float) PyFloat_AsDouble(o);
} else {
PyErr_SetString(PyExc_ValueError, "Sequence elements must be numbers");
SWIG_fail;
}
}
$1 = temp; }  In this example, the variable temp allocates a small array on the C stack. The typemap then populates this array and passes it to the underlying C function. When used from Python, the typemap allows the following type of function call: 在这个例子中，变量 temp 在 C 栈上分配了一个小数组。然后，类型映射将填充此数组，并将其传递给基础 C 函数。 当从 Python 使用时，类型映射允许以下类型的函数调用： >>> set_vector(type, [ 1, 2.5, 5, 20 ])  If you wanted to generalize the typemap to apply to arrays of all dimensions you might write this: 如果要泛化类型映射以应用于所有维度的数组，则可以这样编写： %typemap(in) float value[ANY] (float temp[$1_dim0]) {
int i;
if (!PySequence_Check($input)) { PyErr_SetString(PyExc_ValueError, "Expected a sequence"); SWIG_fail; } if (PySequence_Length($input) != $1_dim0) { PyErr_SetString(PyExc_ValueError, "Size mismatch. Expected$1_dim0 elements");
SWIG_fail;
}
for (i = 0; i < $1_dim0; i++) { PyObject *o = PySequence_GetItem($input, i);
if (PyNumber_Check(o)) {
temp[i] = (float) PyFloat_AsDouble(o);
} else {
PyErr_SetString(PyExc_ValueError, "Sequence elements must be numbers");
SWIG_fail;
}
}
$1 = temp; }  In this example, the special variable $1_dim0 is expanded with the actual array dimensions. Multidimensional arrays can be matched in a similar manner. For example:

PyErr_SetString(PyExc_ValueError, "Expected a sequence");
SWIG_fail;
}
if (PySequence_Length($input) !=$1_dim0) {
PyErr_SetString(PyExc_ValueError, "Size mismatch. Expected $1_dim0 elements"); SWIG_fail; }$1 = (float *) malloc($1_dim0*sizeof(float)); for (i = 0; i <$1_dim0; i++) {
PyObject *o = PySequence_GetItem($input, i); if (PyNumber_Check(o)) {$1[i] = (float) PyFloat_AsDouble(o);
} else {
free($1); PyErr_SetString(PyExc_ValueError, "Sequence elements must be numbers"); SWIG_fail; } } } %typemap(freearg) float value[ANY] { if ($1) free($1); }  In this case, an array is allocated using malloc. The freearg typemap is then used to release the argument after the function has been called. Another common use of array typemaps is to provide support for array structure members. Due to subtle differences between pointers and arrays in C, you can't just "assign" to a array structure member. Instead, you have to explicitly copy elements into the array. For example, suppose you had a structure like this: 在这种情况下，使用 malloc 分配数组。然后，在调用函数后，使用 freearg 类型映射释放参数。 数组类型映射的另一个常见用途是为数组结构体成员提供支持。由于 C 语言中的指针和数组之间存在细微的差异，因此你不能只是“分配”给数组结构体成员。相反，你必须将元素显式复制到数组中。例如，假设你具有这样的结构体： struct SomeObject { float value[4]; ... };  When SWIG runs, it won't produce any code to set the vec member. You may even get a warning message like this: SWIG 运行时，不会产生任何代码来设置 vec 成员。你甚至可能收到以下警告消息： $ swig -python  example.i
example.i:10: Warning 462: Unable to set variable of type float [4].


These warning messages indicate that SWIG does not know how you want to set the vec field.

To fix this, you can supply a special "memberin" typemap like this:

%typemap(memberin) float [ANY] {
int i;
for (i = 0; i < $1_dim0; i++) {$1[i] = $input[i]; } }  The memberin typemap is used to set a structure member from data that has already been converted from the target language to C. In this case, $input is the local variable in which converted input data is stored. This typemap then copies this data into the structure.

When combined with the earlier typemaps for arrays, the combination of the "in" and "memberin" typemap allows the following usage:

memberin 类型映射用于从已经从目标语言转换为 C 的数据中设置结构体成员。在这种情况下，$input 是局部变量，用于存储转换后的输入数据。然后，此类型映射将此数据复制到结构体中。 当与早期的数组类型映射结合使用时，inmemberin 类型映射的组合允许以下用法： >>> s = SomeObject() >>> s.x = [1, 2.5, 5, 10]  Related to structure member input, it may be desirable to return structure members as a new kind of object. For example, in this example, you will get very odd program behavior where the structure member can be set nicely, but reading the member simply returns a pointer: 与结构体成员输入有关，可能希望将结构体成员作为一种新的对象返回。例如，在此示例中，你将获得非常奇怪的程序行为，可以很好地设置结构体成员，但是读取成员仅返回一个指针： >>> s = SomeObject() >>> s.x = [1, 2.5, 5, 10] >>> print s.x _1008fea8_p_float >>>  To fix this, you can write an "out" typemap. For example: 要修正的话，你可以使用 out 类型映射。例如： %typemap(out) float [ANY] { int i;$result = PyList_New($1_dim0); for (i = 0; i <$1_dim0; i++) {
PyObject *o = PyFloat_FromDouble((double) $1[i]); PyList_SetItem($result, i, o);
}
}


Now, you will find that member access is quite nice:

>>> s = SomeObject()
>>> s.x = [1, 2.5, 5, 10]
>>> print s.x
[ 1, 2.5, 5, 10]


Compatibility Note: SWIG1.1 used to provide a special "memberout" typemap. However, it was mostly useless and has since been eliminated. To return structure members, simply use the "out" typemap.

### 11.6.2 用类型映射的实现限制

One particularly interesting application of typemaps is the implementation of argument constraints. This can be done with the "check" typemap. When used, this allows you to provide code for checking the values of function arguments. For example:

%module math

%typemap(check) double posdouble {
if ($1 < 0) { croak("Expecting a positive number"); } } ... double sqrt(double posdouble);  This provides a sanity check to your wrapper function. If a negative number is passed to this function, a Perl exception will be raised and your program terminated with an error message. This kind of checking can be particularly useful when working with pointers. For example: 这为包装器函数提供了完整性检查。如果将负数传递给此函数，则会引发 Perl 异常，并且你的程序终止并显示错误消息。 在使用指针时，这种检查特别有用。例如： %typemap(check) Vector * { if ($1 == 0) {
PyErr_SetString(PyExc_TypeError, "NULL Pointer not allowed");
SWIG_fail;
}
}


will prevent any function involving a Vector * from accepting a NULL pointer. As a result, SWIG can often prevent a potential segmentation faults or other run-time problems by raising an exception rather than blindly passing values to the underlying C/C++ program.

## 11.7 多目标语言的类型映射

The code within typemaps is usually language dependent, however, many target languages support the same typemaps. In order to distinguish typemaps across different languages, the preprocessor should be used. For example, the "in" typemap for Perl and Ruby could be written as:

#if defined(SWIGPERL)
%typemap(in) int "$1 = ($1_ltype) SvIV($input);" #elif defined(SWIGRUBY) %typemap(in) int "$1 = NUM2INT($input);" #else #warning no "in" typemap defined #endif  The full set of language specific macros is defined in the Conditional Compilation section. The example above also shows a common approach of issuing a warning for an as yet unsupported language. Compatibility note: In SWIG-1.1 different languages could be distinguished with the language name being put within the %typemap directive, for example, %typemap(ruby, in) int "$1 = NUM2INT($input);". 条件编译章节中定义了特定于语言的完整宏集合。上面的示例还显示了针对尚不支持的语言发出警告的常见方法。 注意兼容性：在 SWIG-1.1中，可以通过在 %typemap 指令中放入语言名称来区分不同的语言，例如，%typemap(ruby, in) int "$1 = NUM2INT($input);" ## 11.8 返回值时的最优代码生成 The "out" typemap is the main typemap for return types. This typemap supports an optional attribute flag called "optimal", which is for reducing temporary variables and the amount of generated code, thereby giving the compiler the opportunity to use return value optimization for generating faster executing code. It only really makes a difference when returning objects by value and has some limitations on usage, as explained later on. When a function returns an object by value, SWIG generates code that instantiates the default type on the stack then assigns the value returned by the function call to it. A copy of this object is then made on the heap and this is what is ultimately stored and used from the target language. This will be clearer considering an example. Consider running the following code through SWIG: out 类型映射是返回类型的主要类型映射。此类型映射支持一个称为 optimal 的可选属性标志，该标志用于减少临时变量和所生成的代码量，从而使编译器有机会使用返回值优化来生成执行速度更快的代码。如后面所述，只有在按值返回对象时，它才真正有所不同，并且在用法上有一些限制。 当函数按值返回对象时，SWIG 会生成代码，该代码实例化堆栈上的默认类型，然后将函数调用返回的值分配给它。然后在堆上创建此对象的副本，这是最终从目标语言存储和使用的对象。考虑一个例子，这将更加清楚。考虑通过 SWIG 运行以下代码： %typemap(out) SWIGTYPE %{$result = new $1_ltype((const$1_ltype &)$1); %} %inline %{ #include <iostream> using namespace std; struct XX { XX() { cout << "XX()" << endl; } XX(int i) { cout << "XX(" << i << ")" << endl; } XX(const XX &other) { cout << "XX(const XX &)" << endl; } XX & operator =(const XX &other) { cout << "operator=(const XX &)" << endl; return *this; } ~XX() { cout << "~XX()" << endl; } static XX create() { return XX(0); } }; %}  The "out" typemap shown is the default typemap for C# when returning objects by value. When making a call to XX::create() from C#, the output is as follows: 当按值返回对象时，显示的 out 类型映射是 C# 的默认类型映射。从 C# 调用 XX::create() 时，输出如下： XX() XX(0) operator=(const XX &) ~XX() XX(const XX &) ~XX() ~XX()  Note that three objects are being created as well as an assignment. Wouldn't it be great if the XX::create() method was the only time a constructor was called? As the method returns by value, this is asking a lot and the code that SWIG generates by default makes it impossible for the compiler to use return value optimisation (RVO). However, this is where the "optimal" attribute in the "out" typemap can help out. If the typemap code is kept the same and just the "optimal" attribute specified like this: 请注意，正在创建三个对象以及一个分配。如果唯一调用构造函数的方法是 XX::create() 方法，那不是很好吗？由于该方法按值返回，因此要求很多，而 SWIG 默认生成的代码使编译器无法使用返回值优化（RVO）。但是，这是 out 类型映射中的 optimal 属性可以提供帮助的地方。如果类型映射代码保持相同，并且仅指定 optimal 属性，如下所示： %typemap(out, optimal="1") SWIGTYPE %{$result = new $1_ltype((const$1_ltype &)$1); %}  then when the code is run again, the output is simply: 再次运行代码，输出很简单： XX(0) ~XX()  How the "optimal" attribute works is best explained using the generated code. Without "optimal", the generated code is: 使用生成的代码可以最好地解释 optimal 属性的工作方式。如果没有 optimal，则生成的代码为： SWIGEXPORT void * SWIGSTDCALL CSharp_XX_create() { void * jresult ; XX result; result = XX::create(); jresult = new XX((const XX &)result); return jresult; }  With the "optimal" attribute, the code is: 有了 optimal 属性，代码为： SWIGEXPORT void * SWIGSTDCALL CSharp_XX_create() { void * jresult ; jresult = new XX((const XX &)XX::create()); return jresult; }  The major difference is the result temporary variable holding the value returned from XX::create() is no longer generated and instead the copy constructor call is made directly from the value returned by XX::create(). With modern compilers implementing RVO, the copy is not actually done, in fact the object is never created on the stack in XX::create() at all, it is simply created directly on the heap. In the first instance, the $1 special variable in the typemap is expanded into result. In the second instance, $1is expanded into XX::create() and this is essentially what the "optimal" attribute is telling SWIG to do. The "optimal" attribute optimisation is not turned on by default as it has a number of restrictions. Firstly, some code cannot be condensed into a simple call for passing into the copy constructor. One common occurrence is when %exception is used. Consider adding the following %exception to the example: 主要区别是 result 临时变量不再保存从 XX::create() 返回的值，而是直接从 XX::create() 返回的值进行复制构造函数调用。使用实现 RVO 的现代编译器，实际上并不会完成复制，实际上，该对象根本不会在 XX::create() 中的堆栈上创建，而只是在堆上直接创建。首先，将类型映射中的 $1 特殊变量扩展为 result。在第二种情况下，将 $1 扩展为 XX::create()，这实际上就是 optimal 属性告诉 SWIG 要做的事情。 默认情况下，optimal 属性优化未启用，因为它有许多限制。首先，某些代码不能被精简为传递给复制构造函数的简单调用。一种常见的情况是使用 %exception。考虑在示例中添加以下 %exception %exception XX::create() %{ try {$action
} catch(const std::exception &e) {
cout << e.what() << endl;
}
%}


SWIG can detect when the "optimal" attribute cannot be used and will ignore it and in this case will issue the following warning:

SWIG 可以检测到何时无法使用 optimal 属性，并将其忽略，在这种情况下，将发出以下警告：

example.i:28: Warning 474: Method XX::create() usage of the optimal attribute ignored
example.i:14: Warning 474: in the out typemap as the following cannot be used to generate
optimal code:
try {
result = XX::create();
} catch(const std::exception &e) {
cout << e.what() << endl;
}


It should be clear that the above code cannot be used as the argument to the copy constructor call, that is, for the $1 substitution. Secondly, if the typemaps uses $1 more than once, then multiple calls to the wrapped function will be made. Obviously that is not very optimal. In fact SWIG attempts to detect this and will issue a warning something like:

example.i:21: Warning 475: Multiple calls to XX::create() might be generated due to
example.i:7: Warning 475: optimal attribute usage in the out typemap.


However, it doesn't always get it right, for example when $1 is within some commented out code. 但是，它并不总是正确，例如，当 $1 在某些注释掉的代码中时。

## 11.9 多参数类型映射

So far, the typemaps presented have focused on the problem of dealing with single values. For example, converting a single input object to a single argument in a function call. However, certain conversion problems are difficult to handle in this manner. As an example, consider the example at the very beginning of this chapter:

int foo(int argc, char *argv[]);


Suppose that you wanted to wrap this function so that it accepted a single list of strings like this:

>>> foo(["ale", "lager", "stout"])


To do this, you not only need to map a list of strings to char *argv[], but the value of int argc is implicitly determined by the length of the list. Using only simple typemaps, this type of conversion is possible, but extremely painful. Multi-argument typemaps help in this situation.

A multi-argument typemap is a conversion rule that specifies how to convert a single object in the target language to a set of consecutive function arguments in C/C++. For example, the following multi-argument maps perform the conversion described for the above example:

%typemap(in) (int argc, char *argv[]) {
int i;
if (!PyList_Check($input)) { PyErr_SetString(PyExc_ValueError, "Expecting a list"); SWIG_fail; }$1 = PyList_Size($input);$2 = (char **) malloc(($1+1)*sizeof(char *)); for (i = 0; i <$1; i++) {
PyObject *s = PyList_GetItem($input, i); if (!PyString_Check(s)) { free($2);
PyErr_SetString(PyExc_ValueError, "List items must be strings");
SWIG_fail;
}
$2[i] = PyString_AsString(s); }$2[i] = 0;
}

%typemap(freearg) (int argc, char *argv[]) {
if ($2) free($2);
}

/* Required for C++ method overloading */
%typecheck(SWIG_TYPECHECK_STRING_ARRAY) (int argc, char *argv[]) {
$1 = PyList_Check($input) ? 1 : 0;
}


A multi-argument map is always specified by surrounding the arguments with parentheses as shown. For example:

%typemap(in) (int argc, char *argv[]) { ... }


Within the typemap code, the variables $1, $2, and so forth refer to each type in the map. All of the usual substitutions apply--just use the appropriate $1 or $2 prefix on the variable name (e.g., $2_type, $1_ltype, etc.)

Multi-argument typemaps always have precedence over simple typemaps and SWIG always performs longest-match searching. Therefore, you will get the following behavior:

%typemap(in) int argc                              { ... typemap 1 ... }
%typemap(in) (int argc, char *argv[])              { ... typemap 2 ... }
%typemap(in) (int argc, char *argv[], char *env[]) { ... typemap 3 ... }

int foo(int argc, char *argv[]);                   // Uses typemap 2
int bar(int argc, int x);                          // Uses typemap 1
int spam(int argc, char *argv[], char *env[]);     // Uses typemap 3


It should be stressed that multi-argument typemaps can appear anywhere in a function declaration and can appear more than once. For example, you could write this:

%typemap(in) (int scount, char *swords[]) { ... }
%typemap(in) (int wcount, char *words[]) { ... }

void search_words(int scount, char *swords[], int wcount, char *words[], int maxcount);


Other directives such as %apply and %clear also work with multi-argument maps. For example:

%apply (int argc, char *argv[]) {
(int scount, char *swords[]),
(int wcount, char *words[])
};
...
%clear (int scount, char *swords[]), (int wcount, char *words[]);
...


Don't forget to also provide a suitable typemap for overloaded functions, such as %typecheck shown for foo above. This is only required if the function is overloaded in C++.

Although multi-argument typemaps may seem like an exotic, little used feature, there are several situations where they make sense. First, suppose you wanted to wrap functions similar to the low-level read() and write() system calls. For example:

typedef unsigned int size_t;

int read(int fd, void *rbuffer, size_t len);
int write(int fd, void *wbuffer, size_t len);


As is, the only way to use the functions would be to allocate memory and pass some kind of pointer as the second argument---a process that might require the use of a helper function. However, using multi-argument maps, the functions can be transformed into something more natural. For example, you might write typemaps like this:

// typemap for an outgoing buffer
%typemap(in) (void *wbuffer, size_t len) {
if (!PyString_Check($input)) { PyErr_SetString(PyExc_ValueError, "Expecting a string"); SWIG_fail; }$1 = (void *) PyString_AsString($input);$2 = PyString_Size($input); } // typemap for an incoming buffer %typemap(in) (void *rbuffer, size_t len) { if (!PyInt_Check($input)) {
PyErr_SetString(PyExc_ValueError, "Expecting an integer");
SWIG_fail;
}
$2 = PyInt_AsLong($input);
if ($2 < 0) { PyErr_SetString(PyExc_ValueError, "Positive integer expected"); SWIG_fail; }$1 = (void *) malloc($2); } // Return the buffer. Discarding any previous return result %typemap(argout) (void *rbuffer, size_t len) { Py_XDECREF($result);   /* Blow away any previous result */
if (result < 0) {      /* Check for I/O error */
free($1); PyErr_SetFromErrno(PyExc_IOError); return NULL; }$result = PyString_FromStringAndSize($1, result); free($1);
}


(note: In the above example, $result and result are two different variables. result is the real C datatype that was returned by the function. $result is the scripting language object being returned to the interpreter.).

Now, in a script, you can write code that simply passes buffers as strings like this:

（注意：在上面的示例中，$resultresult 是两个不同的变量。result 是函数返回的实际 C 数据类型。$result 是要返回到解释器的脚本语言对象 ）。

>>> f = example.open("Makefile")
>>> example.read(f, 40)
'TOP        = ../..\nSWIG       = $(TOP)/.' >>> example.read(f, 40) './swig\nSRCS = example.c\nTARGET ' >>> example.close(f) 0 >>> g = example.open("foo", example.O_WRONLY | example.O_CREAT, 0644) >>> example.write(g, "Hello world\n") 12 >>> example.write(g, "This is a test\n") 15 >>> example.close(g) 0 >>>  A number of multi-argument typemap problems also arise in libraries that perform matrix-calculations--especially if they are mapped onto low-level Fortran or C code. For example, you might have a function like this: 在执行矩阵计算的库中，还会出现许多多参数类型映射问题，尤其是如果将它们映射到低级 Fortran 或 C 代码上。例如，你可能具有以下函数： int is_symmetric(double *mat, int rows, int columns);  In this case, you might want to pass some kind of higher-level object as an matrix. To do this, you could write a multi-argument typemap like this: 在这种情况下，你可能需要传递某种高级对象作为矩阵。为此，你可以编写一个如下所示的多参数类型映射： %typemap(in) (double *mat, int rows, int columns) { MatrixObject *a; a = GetMatrixFromObject($input);     /* Get matrix somehow */

/* Get matrix properties */
$1 = GetPointer(a);$2 = GetRows(a);
$3 = GetColumns(a); }  This kind of technique can be used to hook into scripting-language matrix packages such as Numeric Python. However, it should also be stressed that some care is in order. For example, when crossing languages you may need to worry about issues such as row-major vs. column-major ordering (and perform conversions if needed). Note that multi-argument typemaps cannot deal with non-consecutive C/C++ arguments; a workaround such as a helper function re-ordering the arguments to make them consecutive will need to be written. 这种技术可用于连接脚本语言矩阵包，例如 Numeric Python。但是，还应该强调，一定要谨慎。例如，在使用多种语言时，你可能需要担心行优先与列优先的排序（并在需要时执行转换）。注意，多参数类型映射不能处理非连续的 C/C++ 参数。需要编写一种变通方法，例如辅助函数，将参数重新排序以使其连续。 ## 11.10 类型映射警告 Warnings can be added to typemaps so that SWIG generates a warning message whenever the typemap is used. See the information in the issuing warnings section. 可以将警告添加到类型映射，以便每当使用类型映射时 SWIG 都会生成警告消息。请参阅发布警告章节中的信息。 ## 11.11 类型映射片段 The primary purpose of fragments is to reduce code bloat that repeated use of typemap code can lead to. Fragments are snippets of code that can be thought of as code dependencies of a typemap. If a fragment is used by more than one typemap, then the snippet of code within the fragment is only generated once. Code bloat is typically reduced by moving typemap code into a support function and then placing the support function into a fragment. For example, if you have a very long typemap 片段的主要目的是减少重复使用类型映射代码可能导致的代码膨胀。片段是代码片段，可以将其视为类型映射的代码依赖项。如果一个片段被多个类型映射使用，则该片段内的代码片段仅生成一次。通常可以通过将类型映射代码移入支持函数，然后将支持函数放入片段中来减少代码膨胀。 例如，如果你的类型映射很长 %typemap(in) MyClass * { MyClass *value = 0; ... many lines of marshalling code ...$result = value;
}


the same marshalling code is often repeated in several typemaps, such as "in", "varin", "directorout", etc. SWIG copies the code for each argument that requires the typemap code, easily leading to code bloat in the generated code. To eliminate this, define a fragment that includes the common marshalling code:

%fragment("AsMyClass", "header") {
MyClass *AsMyClass(PyObject *obj) {
MyClass *value = 0;

... many lines of marshalling code  ...

return value;
}
}

%typemap(in, fragment="AsMyClass") MyClass * {
$result = AsMyClass($input);
}

%typemap(varin, fragment="AsMyClass") MyClass * {
$result = AsMyClass($input);
}


When the "in" or "varin" typemaps for MyClass are required, the contents of the fragment called "AsMyClass" is added to the "header" section within the generated code, and then the typemap code is emitted. Hence, the method AsMyClass will be generated into the wrapper code before any typemap code that calls it.

To define a fragment you need a fragment name, a section name for generating the fragment code into, and the code itself. See Code insertion blocks for a full list of section names. Usually the section name used is "header". Different delimiters can be used:

%fragment("my_name", "header") %{ ... %}
%fragment("my_name", "header") { ... }
%fragment("my_name", "header") " ... "


and these follow the usual preprocessing rules mentioned in the Preprocessing delimiters section. The following are some rules and guidelines for using fragments:

1. A fragment is added to the wrapping code only once. When using the MyClass * typemaps above and wrapping the method:

1. 一个片段仅被添加到包装代码一次。当使用上面的 MyClass * 类型映射并包装方法时：
void foo(MyClass *a, MyClass *b);


the generated code will look something like:

MyClass *AsMyClass(PyObject *obj) {
...
}

void _wrap_foo(...) {
....
arg1 = AsMyClass(obj1);
arg2 = AsMyClass(obj2);
...
foo(arg1, arg2);
}


even as there is duplicated typemap code to process both a and b, the AsMyClass method will be defined only once.

1. A fragment should only be defined once. If there is more than one definition, the first definition is the one used. All other definitions are silently ignored. For example, if you have

1. 一个片段只能定义一次。如果有多个定义，则第一个定义是使用的定义。所有其他定义都被忽略。例如，如果你有
%fragment("AsMyClass", "header") { ...definition 1... }
....
%fragment("AsMyClass", "header") { ...definition 2... }


only the first definition is used. In this way you can override the default fragments in a SWIG library by defining your fragment before the library %include. Note that this behavior is the opposite to typemaps, where the last typemap defined/applied prevails. Fragments follow the first-in-first-out convention since they are intended to be global, while typemaps are intended to be locally specialized.

1. Fragment names cannot contain commas.

2. A fragment can use one or more additional fragments, for example:

1. 片段名称不能包含逗号。
2. 一个片段可以使用一个或多个其他片段，例如：
%fragment("<limits.h>", "header") {
%#include <limits.h>
}

%fragment("AsMyClass", "header", fragment="<limits.h>") {
MyClass *AsMyClass(PyObject *obj) {
MyClass *value = 0;

... some marshalling code  ...

if  (ival < CHAR_MIN /*defined in <limits.h>*/) {
...
} else {
...
}
...
return value;
}
}


in this case, when the "AsMyClass" fragment is emitted, it also triggers the inclusion of the "<limits.h>" fragment.

1. A fragment can have dependencies on a number of other fragments, for example:

1. 一个片段可以依赖于许多其他片段，例如：
%fragment("bigfragment", "header", fragment="frag1", fragment="frag2", fragment="frag3") "";


When the "bigfragment" is used, the three dependent fragments "frag1", "frag2" and "frag3" are also pulled in. Note that as "bigframent" is empty (the empty string - ""), it does not add any code itself, but merely triggers the inclusion of the other fragments.

1. A typemap can also use more than one fragment, but since the syntax is different, you need to specify the dependent fragments in a comma separated list. Consider:

1. 一个类型映射也可以使用多个片段，但是由于语法不同，你需要在逗号分隔的列表中指定从属片段。考虑：
%typemap(in, fragment="frag1, frag2, frag3") {...}


which is equivalent to:

%typemap(in, fragment="bigfragment") {...}


when used with the "bigfragment" defined above.

1. Finally, you can force the inclusion of a fragment at any point in the generated code as follows:

1. 最后，你可以按以下步骤在生成的代码中的任何位置强制包含片段：
%fragment("bigfragment");


which is very useful inside a template class, for example.

Most readers will probably want to skip the next two sub-sections on advanced fragment usage unless a desire to really get to grips with some powerful but tricky macro and fragment usage that is used in parts of the SWIG typemap library.

### 11.11.1 片段类型特化

Fragments can be type specialized. The syntax is as follows:

%fragment("name", "header") { ...a type independent fragment... }
%fragment("name"{type}, "header") { ...a type dependent fragment...  }


where type is a C/C++ type. Like typemaps, fragments can also be used inside templates, for example:

template <class T>
struct A {
%fragment("incode"{A<T>}, "header") {
... 'incode' specialized fragment ...
}

%typemap(in, fragment="incode"{A<T>}) {
... here we use the 'type specialized' fragment "incode"{A<T>} ...
}
};


### 11.11.2 片段与自动类型映射特化

Since fragments can be type specialized, they can be elegantly used to specialize typemaps. For example, if you have something like:

%fragment("incode"{float}, "header") {
float in_method_float(PyObject *obj) {
...
}
}

%fragment("incode"{long}, "header") {
float in_method_long(PyObject *obj) {
...
}
}

// %my_typemaps macro definition
%define %my_typemaps(Type)
%typemap(in, fragment="incode"{Type}) Type {
value = in_method_##Type(obj);
}
%enddef

%my_typemaps(float);
%my_typemaps(long);


then the proper "incode"{float} or "incode"{long} fragment will be used, and the in_method_floatand in_method_long methods will be called whenever the float or long types are used as input parameters.

This feature is used a lot in the typemaps shipped in the SWIG library for some scripting languages. The interested (or very brave) reader can take a look at the fragments.swg file shipped with SWIG to see this in action.

SWIG 库附带的类型映射中的某些脚本语言经常使用此功能。有兴趣的（或非常勇敢的）读者可以查看 SWIG 附带的 fragments.swg 文件，以了解实际情况。

## 11.12 运行时类型检查器

Most scripting languages need type information at run-time. This type information can include how to construct types, how to garbage collect types, and the inheritance relationships between types. If the language interface does not provide its own type information storage, the generated SWIG code needs to provide it.

Requirements for the type system:

• Store inheritance and type equivalence information and be able to correctly re-create the type pointer.
• Share type information between modules.
• Modules can be loaded in any order, regardless of actual type dependency.
• Avoid the use of dynamically allocated memory, and library/system calls in general.
• Provide a reasonably fast implementation, minimizing the lookup time for all language modules.
• Custom, language specific information can be attached to types.
• Modules can be unloaded from the type system.

• 存储继承和类型等效信息，并能够正确地重新创建类型指针。
• 在模块之间共享类型信息。
• 模块可以以任何顺序加载，而不管实际的类型依赖性如何。
• 避免一般使用动态分配的内存和库/系统调用。
• 提供合理快速的实施，以最小化所有语言模块的查找时间。
• 自定义，特定于语言的信息可以附加到类型上。
• 可以从类型系统中卸载模块。

### 11.12.1 实现

The run-time type checker is used by many, but not all, of SWIG's supported target languages. The run-time type checker features are not required and are thus not used for statically typed languages such as Java and C#. The scripting and scheme based languages rely on it and it forms a critical part of SWIG's operation for these languages.

When pointers, arrays, and objects are wrapped by SWIG, they are normally converted into typed pointer objects. For example, an instance of Foo * might be a string encoded like this:

SWIG 支持的许多（但不是全部）目标语言都使用运行时类型检查器。运行时类型检查器功能不是必需的，因此不用于 Java 和 C# 之类的静态类型语言。基于脚本和框架的语言都依赖它，并且它构成了 SWIG 对这些语言的操作的关键部分。

_108e688_p_Foo


At a basic level, the type checker simply restores some type-safety to extension modules. However, the type checker is also responsible for making sure that wrapped C++ classes are handled correctly---especially when inheritance is used. This is especially important when an extension module makes use of multiple inheritance. For example:

class Foo {
public:
int x;
};

class Bar {
public:
int y;
};

class FooBar : public Foo, public Bar {
public:
int z;
};


When the class FooBar is organized in memory, it contains the contents of the classes Foo and Bar as well as its own data members. For example:

FooBar --> | -----------|  <-- Foo
| int x |
| ----- |<-- Bar
| int y        |
| ------------ |
| int z        |
| ------------ |


Because of the way that base class data is stacked together, the casting of a Foobar * to either of the base classes may change the actual value of the pointer. This means that it is generally not safe to represent pointers using a simple integer or a bare void *---type tags are needed to implement correct handling of pointer values (and to make adjustments when needed).

In the wrapper code generated for each language, pointers are handled through the use of special type descriptors and conversion functions. For example, if you look at the wrapper code for Python, you will see code similar to the following (simplified for brevity):

if (!SWIG_IsOK(SWIG_ConvertPtr(obj0, (void **) &arg1, SWIGTYPE_p_Foo, 0))) {
SWIG_exception_fail(SWIG_TypeError, "in method 'GrabVal', expecting type Foo");
}


In this code, SWIGTYPE_p_Foo is the type descriptor that describes Foo *. The type descriptor is actually a pointer to a structure that contains information about the type name to use in the target language, a list of equivalent typenames (via typedef or inheritance), and pointer value handling information (if applicable). The SWIG_ConvertPtr() function is simply a utility function that takes a pointer object in the target language and a type-descriptor object and uses this information to generate a C++ pointer. The SWIG_IsOKmacro checks the return value for errors and SWIG_exception_fail can be called to raise an exception in the target language. However, the exact name and calling conventions of the conversion function depends on the target language (see language specific chapters for details).

The actual type code is in swigrun.swg, and gets inserted near the top of the generated swig wrapper file. The phrase "a type X that can cast into a type Y" means that given a type X, it can be converted into a type Y. In other words, X is a derived class of Y or X is a typedef of Y. The structure to store type information looks like this:

/* Structure to store information on one type */
typedef struct swig_type_info {
const char *name;             /* mangled name of this type */
const char *str;              /* human readable name for this type */
swig_dycast_func dcast;       /* dynamic cast function down a hierarchy */
struct swig_cast_info *cast;  /* Linked list of types that can cast into this type */
void *clientdata;             /* Language specific type data */
} swig_type_info;

/* Structure to store a type and conversion function used for casting */
typedef struct swig_cast_info {
swig_type_info *type;          /* pointer to type that is equivalent to this type */
swig_converter_func converter; /* function to cast the void pointers */
struct swig_cast_info *next;   /* pointer to next cast in linked list */
struct swig_cast_info *prev;   /* pointer to the previous cast */
} swig_cast_info;


Each swig_type_info stores a linked list of types that it is equivalent to. Each entry in this doubly linked list stores a pointer back to another swig_type_info structure, along with a pointer to a conversion function. This conversion function is used to solve the above problem of the FooBar class, correctly returning a pointer to the type we want.

The basic problem we need to solve is verifying and building arguments passed to functions. So going back to the SWIG_ConvertPtr() function example from above, we are expecting a Foo * and need to check if obj0 is in fact a Foo *. From before, SWIGTYPE_p_Foo is just a pointer to the swig_type_infostructure describing Foo *. So we loop through the linked list of swig_cast_info structures attached to SWIGTYPE_p_Foo. If we see that the type of obj0 is in the linked list, we pass the object through the associated conversion function and then return a positive. If we reach the end of the linked list without a match, then obj0 can not be converted to a Foo * and an error is generated.

Another issue needing to be addressed is sharing type information between multiple modules. More explicitly, we need to have ONE swig_type_info for each type. If two modules both use the type, the second module loaded must lookup and use the swig_type_info structure from the module already loaded. Because no dynamic memory is used and the circular dependencies of the casting information, loading the type information is somewhat tricky, and not explained here. A complete description is in the Lib/swiginit.swg file (and near the top of any generated file).

Each module has one swig_module_info structure which looks like this:

/* Structure used to store module information
* Each module generates one structure like this, and the runtime collects
* all of these structures and stores them in a circularly linked list.*/
typedef struct swig_module_info {
swig_type_info **types;         /* Array of pointers to swig_type_info structs in this module */
int size;                       /* Number of types in this module */
struct swig_module_info *next;  /* Pointer to next element in circularly linked list */
swig_type_info **type_initial;  /* Array of initially generated type structures */
swig_cast_info **cast_initial;  /* Array of initially generated casting structures */
void *clientdata;               /* Language specific module data */
} swig_module_info;


Each module stores an array of pointers to swig_type_info structures and the number of types in this module. So when a second module is loaded, it finds the swig_module_info structure for the first module and searches the array of types. If any of its own types are in the first module and have already been loaded, it uses those swig_type_info structures rather than creating new ones. These swig_module_info structures are chained together in a circularly linked list.

### 11.12.2 使用

This section covers how to use these functions from typemaps. To learn how to call these functions from external files (not the generated _wrap.c file), see the External access to the run-time system section.

When pointers are converted in a typemap, the typemap code often looks similar to this:

%typemap(in) Foo * {
if (!SWIG_IsOK(SWIG_ConvertPtr($input, (void **) &$1, $1_descriptor, 0))) { SWIG_exception_fail(SWIG_TypeError, "in method '$symname', expecting type Foo");
}
}


The most critical part is the typemap is the use of the $1_descriptor special variable. When placed in a typemap, this is expanded into the SWIGTYPE_* type descriptor object above. As a general rule, you should always use $1_descriptor instead of trying to hard-code the type descriptor name directly.

There is another reason why you should always use the $1_descriptor variable. When this special variable is expanded, SWIG marks the corresponding type as "in use." When type-tables and type information is emitted in the wrapper file, descriptor information is only generated for those datatypes that were actually used in the interface. This greatly reduces the size of the type tables and improves efficiency. Occasionally, you might need to write a typemap that needs to convert pointers of other types. To handle this, the special variable macro $descriptor(type) covered earlier can be used to generate the SWIG type descriptor name for any C datatype. For example:

%typemap(in) Foo * {
if (!SWIG_IsOK(SWIG_ConvertPtr($input, (void **) &$1, $1_descriptor, 0))) { Bar *temp; if (!SWIG_IsOK(SWIG_ConvertPtr($input, (void **) &temp, $descriptor(Bar *), 0))) { SWIG_exception_fail(SWIG_TypeError, "in method '$symname', expecting type Foo or Bar");
}
$1 = (Foo *)temp; } }  The primary use of $descriptor(type) is when writing typemaps for container objects and other complex data structures. There are some restrictions on the argument---namely it must be a fully defined C datatype. It can not be any of the special typemap variables.

In certain cases, SWIG may not generate type-descriptors like you expect. For example, if you are converting pointers in some non-standard way or working with an unusual combination of interface files and modules, you may find that SWIG omits information for a specific type descriptor. To fix this, you may need to use the %types directive. For example:

$descriptor(type) 的主要用途是为容器对象和其他复杂数据结构编写类型映射时。参数有一些限制——即它必须是完全定义的 C 数据类型。它不能是任何特殊的类型映射变量。 在某些情况下，SWIG 可能不会生成你期望的类型描述符。例如，如果你以某种非标准的方式转换指针或使用接口文件和模块的异常组合，则可能会发现 SWIG 忽略了特定类型描述符的信息。为了解决这个问题，你可能需要使用 %types 指令。例如： %types(int *, short *, long *, float *, double *);  When %types is used, SWIG generates type-descriptor information even if those datatypes never appear elsewhere in the interface file. Further details about the run-time type checking can be found in the documentation for individual language modules. Reading the source code may also help. The file Lib/swigrun.swg in the SWIG library contains all of the source of the generated code for type-checking. This code is also included in every generated wrapped file so you probably just look at the output of SWIG to get a better sense for how types are managed. 当使用 %types时，SWIG 会生成类型描述符信息，即使这些数据类型从不出现在接口文件的其他位置。 有关运行时类型检查的更多详细信息，请参见各个语言模块的文档。阅读源代码也可能会有所帮助。SWIG 库中的 Lib/swigrun.swg 文件包含用于类型检查的生成代码的所有源。该代码也包含在每个生成的包装文件中，因此你可能只需查看 SWIG 的输出即可更好地了解如何管理类型。 ## 11.13 类型映射与重载 This section does not apply to the statically typed languages like Java and C#, where overloading of the types is handled much like C++ by generating overloaded methods in the target language. In many of the other target languages, SWIG still fully supports C++ overloaded methods and functions. For example, if you have a collection of functions like this: 本章节不适用于 Java 和 C# 等静态类型的语言，在这些类型中，类型的重载与 C++ 一样，是通过在目标语言中生成重载的方法来处理的。在许多其他目标语言中，SWIG 仍完全支持 C++ 重载方法和函数。例如，如果你具有以下功能集合： int foo(int x); int foo(double x); int foo(char *s, int y);  You can access the functions in a normal way from the scripting interpreter: 你可以从脚本解释器以常规方式访问函数： # Python foo(3) # foo(int) foo(3.5) # foo(double) foo("hello", 5) # foo(char *, int) # Tcl foo 3 # foo(int) foo 3.5 # foo(double) foo hello 5 # foo(char *, int)  To implement overloading, SWIG generates a separate wrapper function for each overloaded method. For example, the above functions would produce something roughly like this: 为了实现重载，SWIG 为每个重载方法生成一个单独的包装器函数。例如，以上函数将产生大致如下所示的内容： // wrapper pseudocode _wrap_foo_0(argc, args[]) { // foo(int) int arg1; int result; ... arg1 = FromInteger(args[0]); result = foo(arg1); return ToInteger(result); } _wrap_foo_1(argc, args[]) { // foo(double) double arg1; int result; ... arg1 = FromDouble(args[0]); result = foo(arg1); return ToInteger(result); } _wrap_foo_2(argc, args[]) { // foo(char *, int) char *arg1; int arg2; int result; ... arg1 = FromString(args[0]); arg2 = FromInteger(args[1]); result = foo(arg1, arg2); return ToInteger(result); }  Next, a dynamic dispatch function is generated: 接着生成动态调度函数： _wrap_foo(argc, args[]) { if (argc == 1) { if (IsInteger(args[0])) { return _wrap_foo_0(argc, args); } if (IsDouble(args[0])) { return _wrap_foo_1(argc, args); } } if (argc == 2) { if (IsString(args[0]) && IsInteger(args[1])) { return _wrap_foo_2(argc, args); } } error("No matching function!\n"); }  The purpose of the dynamic dispatch function is to select the appropriate C++ function based on argument types---a task that must be performed at runtime in most of SWIG's target languages. The generation of the dynamic dispatch function is a relatively tricky affair. Not only must input typemaps be taken into account (these typemaps can radically change the types of arguments accepted), but overloaded methods must also be sorted and checked in a very specific order to resolve potential ambiguity. A high-level overview of this ranking process is found in the "SWIG and C++" chapter. What isn't mentioned in that chapter is the mechanism by which it is implemented---as a collection of typemaps. To support dynamic dispatch, SWIG first defines a general purpose type hierarchy as follows: 动态调度函数的目的是根据参数类型选择适当的 C++ 函数，这是大多数 SWIG 目标语言都必须在运行时执行的任务。 动态调度函数的生成是一个比较棘手的事情。不仅必须考虑输入类型映射（这些类型映射可以从根本上改变接受的参数的类型），而且还必须以非常特定的顺序对重载方法进行排序和检查，以解决潜在的歧义。《SWIG 和 C++》一章中提供了有关此排名过程的高级概述。在这一章中没有提到的是实现它的机制——作为类型映射的集合。 为了支持动态调度，SWIG 首先定义通用类型层次结构，如下所示： Symbolic Name Precedence Value ------------------------------ ------------------ SWIG_TYPECHECK_POINTER 0 SWIG_TYPECHECK_VOIDPTR 10 SWIG_TYPECHECK_BOOL 15 SWIG_TYPECHECK_UINT8 20 SWIG_TYPECHECK_INT8 25 SWIG_TYPECHECK_UINT16 30 SWIG_TYPECHECK_INT16 35 SWIG_TYPECHECK_UINT32 40 SWIG_TYPECHECK_INT32 45 SWIG_TYPECHECK_UINT64 50 SWIG_TYPECHECK_INT64 55 SWIG_TYPECHECK_UINT128 60 SWIG_TYPECHECK_INT128 65 SWIG_TYPECHECK_INTEGER 70 SWIG_TYPECHECK_FLOAT 80 SWIG_TYPECHECK_DOUBLE 90 SWIG_TYPECHECK_COMPLEX 100 SWIG_TYPECHECK_UNICHAR 110 SWIG_TYPECHECK_UNISTRING 120 SWIG_TYPECHECK_CHAR 130 SWIG_TYPECHECK_STRING 140 SWIG_TYPECHECK_BOOL_ARRAY 1015 SWIG_TYPECHECK_INT8_ARRAY 1025 SWIG_TYPECHECK_INT16_ARRAY 1035 SWIG_TYPECHECK_INT32_ARRAY 1045 SWIG_TYPECHECK_INT64_ARRAY 1055 SWIG_TYPECHECK_INT128_ARRAY 1065 SWIG_TYPECHECK_FLOAT_ARRAY 1080 SWIG_TYPECHECK_DOUBLE_ARRAY 1090 SWIG_TYPECHECK_CHAR_ARRAY 1130 SWIG_TYPECHECK_STRING_ARRAY 1140  (These precedence levels are defined in swig.swg, a library file that's included by all target language modules.) In this table, the precedence-level determines the order in which types are going to be checked. Low values are always checked before higher values. For example, integers are checked before floats, single values are checked before arrays, and so forth. Using the above table as a guide, each target language defines a collection of "typecheck" typemaps. The following excerpt from the Python module illustrates this: （这些优先级在 swig.swg 中定义，swig.swg 是所有目标语言模块都包含的库文件。） 在此表中，优先级确定要检查的类型的顺序。始终先检查低值，然后再检查高值。例如，在浮点数之前检查整数，在数组之前检查单个值，依此类推。 使用上表作为指导，每种目标语言都定义了 typecheck 类型映射的集合。以下 Python 模块摘录说明了这一点： /* Python type checking rules */ /* Note: %typecheck(X) is a macro for %typemap(typecheck, precedence=X) */ %typecheck(SWIG_TYPECHECK_INTEGER) int, short, long, unsigned int, unsigned short, unsigned long, signed char, unsigned char, long long, unsigned long long, const int &, const short &, const long &, const unsigned int &, const unsigned short &, const unsigned long &, const long long &, const unsigned long long &, enum SWIGTYPE, bool, const bool & {$1 = (PyInt_Check($input) || PyLong_Check($input)) ? 1 : 0;
}

%typecheck(SWIG_TYPECHECK_DOUBLE)
float, double,
const float &, const double &
{
$1 = (PyFloat_Check($input) || PyInt_Check($input) || PyLong_Check($input)) ? 1 : 0;
}

%typecheck(SWIG_TYPECHECK_CHAR) char {
$1 = (PyString_Check($input) && (PyString_Size($input) == 1)) ? 1 : 0; } %typecheck(SWIG_TYPECHECK_STRING) char * {$1 = PyString_Check($input) ? 1 : 0; } %typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, noblock=1) SWIGTYPE * { void *vptr = 0; int res = SWIG_ConvertPtr($input, &vptr, $1_descriptor, 0);$1 = SWIG_IsOK(res) ? 1 : 0;
}

%typecheck(SWIG_TYPECHECK_POINTER) PyObject * {
$1 = ($input != 0);
}


It might take a bit of contemplation, but this code has merely organized all of the basic C++ types, provided some simple type-checking code, and assigned each type a precedence value.

Finally, to generate the dynamic dispatch function, SWIG uses the following algorithm:

• Overloaded methods are first sorted by the number of required arguments.
• Methods with the same number of arguments are then sorted by precedence values of argument types.
• Typecheck typemaps are then emitted to produce a dispatch function that checks arguments in the correct order.

If you haven't written any typemaps of your own, it is unnecessary to worry about the typechecking rules. However, if you have written new input typemaps, you might have to supply a typechecking rule as well. An easy way to do this is to simply copy one of the existing typechecking rules. Here is an example,

• 重载的方法首先按所需参数的数量排序。
• 然后，将具有相同数量参数的方法按参数类型的优先级值排序。
• 然后发出 typecheck 类型映射，以产生一个调度函数，该函数以正确的顺序检查参数。

// Typemap for a C++ string
%typemap(in) std::string {
if (PyString_Check($input)) {$1 = std::string(PyString_AsString($input)); } else { SWIG_exception(SWIG_TypeError, "string expected"); } } // Copy the typecheck code for "char *". %typemap(typecheck) std::string = char *;  The bottom line: If you are writing new typemaps and you are using overloaded methods, you will probably have to write new typecheck code or copy and modify existing typecheck code. If you write a typecheck typemap and omit the precedence level, for example commenting it out as shown below: 底线：如果你正在编写新的类型映射，并且使用的是重载方法，则可能必须编写新的类型检查代码或复制和修改现有的类型检查代码。 如果编写类型检查类型映射并忽略优先级，例如将其注释掉，如下所示： %typemap(typecheck /*, precedence=SWIG_TYPECHECK_INTEGER*/) int {$1 = PyInt_Check($input) ? 1 : 0; }  then the type is given a precedence higher than any other known precedence level and a warning is issued: 然后为该类型赋予比其他任何已知优先级高的优先级，并发出警告 example.i:18: Warning 467: Overloaded method foo(int) not supported (incomplete type checking rule - no precedence level in typecheck typemap for 'int').  Notes: • Typecheck typemaps are not used for non-overloaded methods. Because of this, it is still always necessary to check types in any "in" typemaps. • The dynamic dispatch process is only meant to be a heuristic. There are many corner cases where SWIG simply can't disambiguate types to the same degree as C++. The only way to resolve this ambiguity is to use the %rename directive to rename one of the overloaded methods (effectively eliminating overloading). • Typechecking may be partial. For example, if working with arrays, the typecheck code might simply check the type of the first array element and use that to dispatch to the correct function. Subsequent "in" typemaps would then perform more extensive type-checking. • Make sure you read the section on overloading in the "SWIG and C++" chapter. 注意： • typecheck 类型映射不适用于非重载方法。因此，仍然始终需要检查任何 in 类型映射中的类型。 • 动态调度过程仅是一种启发式方法。在许多特殊情况下，SWIG 不能完全消除类型与 C++ 相同的歧义。解决此歧义的唯一方法是使用 %rename 指令重命名其中一种重载方法（有效消除重载）。 • 类型检查可能是部分的。例如，如果使用数组，则类型检查代码可以简单地检查第一个数组元素的类型，然后使用它来分派给正确的函数。随后的 in 类型映射将执行更广泛的类型检查。 • 确保你已阅读《SWIG 和 C++》一章中有关重载的部分。 ## 11.14 %apply 和 %clear 详情 In order to implement certain kinds of program behavior, it is sometimes necessary to write sets of typemaps. For example, to support output arguments, one often writes a set of typemaps like this: 为了实现某些类型的程序行为，有时有必要编写类型映射集。例如，为了支持输出参数，通常会编写这样的一组类型映射： %typemap(in, numinputs=0) int *OUTPUT (int temp) {$1 = &temp;
}
%typemap(argout) int *OUTPUT {
// return value somehow
}


To make it easier to apply the typemap to different argument types and names, the %apply directive performs a copy of all typemaps from one type to another. For example, if you specify this,

%apply int *OUTPUT { int *retvalue, int32 *output };


then all of the int *OUTPUT typemaps are copied to int *retvalue and int32 *output.

However, there is a subtle aspect of %apply that needs more description. Namely, %apply does not overwrite a typemap rule if it is already defined for the target datatype. This behavior allows you to do two things:

• You can specialize parts of a complex typemap rule by first defining a few typemaps and then using %apply to incorporate the remaining pieces.
• Sets of different typemaps can be applied to the same datatype using repeated %apply directives.

For example:

• 你可以通过首先定义一些类型映射，然后使用 %apply 来合并其余部分来特化复杂类型映射规则的各个部分。
• 可以使用重复的 %apply 指令将不同类型映射的集合应用于相同的数据类型。

%typemap(in) int *INPUT (int temp) {
temp = ... get value from $input ...;$1 = &temp;
}

%typemap(check) int *POSITIVE {
if (*$1 <= 0) { SWIG_exception(SWIG_ValueError, "Expected a positive number!\n"); return NULL; } } ... %apply int *INPUT { int *invalue }; %apply int *POSITIVE { int *invalue };  Since %apply does not overwrite or replace any existing rules, the only way to reset behavior is to use the %clear directive. %clear removes all typemap rules defined for a specific datatype. For example: 由于 %apply 不会覆盖或替换任何现有规则，因此重置行为的唯一方法是使用 %clear 伪指令。%clear 删除为特定数据类型定义的所有类型映射规则。例如： %clear int *invalue;  ## 11.15 在类型映射间传递数据 It is also important to note that the primary use of local variables is to create stack-allocated objects for temporary use inside a wrapper function (this is faster and less-prone to error than allocating data on the heap). In general, the variables are not intended to pass information between different types of typemaps. However, this can be done if you realize that local names have the argument number appended to them. For example, you could do this: 同样重要的是要注意，局部变量的主要用途是创建包装分配的对象，以便在包装器函数内部临时使用（与在堆上分配数据相比，此方法更快且更不容易出错）。通常，这些变量无意在不同类型的类型映射之间传递信息。但是，如果你意识到局部名称后面附加了参数编号，则可以这样做。例如，你可以这样做： %typemap(in) int *(int temp) { temp = (int) PyInt_AsLong($input);
$1 = &temp; } %typemap(argout) int * { PyObject *o = PyInt_FromLong(temp$argnum);
...
}


In this case, the $argnum variable is expanded into the argument number. Therefore, the code will reference the appropriate local such as temp1 and temp2. It should be noted that there are plenty of opportunities to break the universe here and that accessing locals in this manner should probably be avoided. At the very least, you should make sure that the typemaps sharing information have exactly the same types and names. 在这种情况下，$argnum 变量将扩展为参数编号。因此，代码将引用适当的局部变量，例如 temp1temp2。应当指出，这里有很多打破宇宙的机会，应该避免以这种方式访问局部变量。至少，你应该确保共享信息的类型映射具有完全相同的类型和名称。

## 11.16 C++ this 指针

All the rules discussed for typemaps apply to C++ as well as C. However in addition C++ passes an extra parameter into every non-static class method -- the this pointer. Occasionally it can be useful to apply a typemap to this pointer (for example to check and make sure this is non-null before deferencing). Actually, C also has an the equivalent of the this pointer which is used when accessing variables in a C struct.

In order to customise the this pointer handling, target a variable named self in your typemaps. self is the name SWIG uses to refer to the extra parameter in wrapped functions.

For example, if wrapping for Java generation:

%typemap(check) SWIGTYPE *self %{
if (!$1) { SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "invalid native object; delete() likely already called"); return$null;
}
%}


In the above case, the $1 variable is expanded into the argument name that SWIG is using as the thispointer. SWIG will then insert the check code before the actual C++ class method is called, and will raise an exception rather than crash the Java virtual machine. The generated code will look something like: 在上述情况下，将 $1 变量扩展为 SWIG 用作 this 指针的参数名称。然后，SWIG 将在调用实际的 C++ 类方法之前插入检查代码，并且将引发异常而不是使 Java 虚拟机崩溃。生成的代码如下所示：

if (!arg1) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException,
"invalid native object; delete() likely already called");
return ;
}
(arg1)->wrappedFunction(...);


Note that if you have a parameter named self then it will also match the typemap. One work around is to create an interface file that wraps the method, but gives the argument a name other than self.

## 11.17 到哪去找更多的信息？

The best place to find out more information about writing typemaps is to look in the SWIG library. Most language modules define all of their default behavior using typemaps. These are found in files such aspython.swg, perl5.swg, tcl8.swg and so forth. The typemaps.i file in the library also contains numerous examples. You should look at these files to get a feel for how to define typemaps of your own. Some of the language modules support additional typemaps and further information is available in the individual chapters for each target language. There you may also find more hands-on practical examples.

posted @ 2020-06-07 22:25  xuruilong100  阅读(151)  评论(0编辑  收藏