处理列表、数组和其它表达式
MathLink 可以与外部程序交换任何类型的数据. 对于更常用的数据类型,需要在
MathLink 模板文件中给出适当的

或

规格.
基本类型规定.
这里是一个函数的
MathLink 模板,该函数的变量是一个整数列表.
:Begin:
:Function: h
:Pattern: h[a_List]
:Arguments: {a}
:ArgumentTypes: {IntegerList}
:ReturnType: Integer
:End:
这里是该函数的 C 源代码. 注意,额外的变量

用来传递列表的长度.
int h(int *a, long alen) {
int i, tot=0;
for(i=0; i<alen; i++)
tot += a[i];
return tot;
}
安装一个包含有函数

规定的外部程序.
| Out[1]= |  |
| Out[2]= |  |
这个与模式

不匹配,所有没有调用外部程序.
| Out[3]= |  |
这里的模式是匹配的,但列表中的元素与外部代码中的类型不同,所以返回到
$Failed.
| Out[4]= |  |
变量的这几种基本类型可以混合使用. 但使用

或

时,在 C 程序中必须包含一个额外的变量去代表该列表的长度.
这是一个

指定.
:ArgumentTypes: {IntegerList, RealList, Integer}
void f(int *a, long alen, double *b, long blen, int c)
注意,
MathLink 把一个列表传递给 C 程序时,它的第一个元素在 C 中标准位置是零,而不是像在
Mathematica 中的那样标准位置是 1.
另外,按照 C 标准,用
String 规定的字符串传递为

对象,用

空字节结束.
"MathLink 程序的可移植性" 节中将讨论怎样处理特殊字符.
| MLPutInteger32(stdlink,int i) | 放入单个整数 |
| MLPutReal64(stdlink,double x) | 放入单个浮点数 |
| MLPutInteger32List(stdlink,int*a,int n) |
| 放入从位置 a 开始的 n 个整数列表 |
| MLPutReal64List(stdlink,double*a,int n) |
| 放入从位置 a 开始的 n 个浮点数列表 |
| MLPutInteger32Array(stdlink,int*a,int*dims,NULL,int d) |
| 放入一个整数阵列去形成一个深度为 d 维数为 dims 的列表 |
| MLPutReal64Array(stdlink,double*a,int*dims,NULL,int d) |
| 放入一个浮点数阵列 |
| MLPutString(stdlink,char*s) | 放入一个字符串 |
| MLPutSymbol(stdlink,char*s) | 放入一个字符串作为符号名 |
| MLPutFunction(stdlink,char*s,int n) |
| 开始放一个头部为 s,有 n 个变量的函数 |
向 Mathematica 送数据的 MathLink 函数.
在使用
MathLink 模板文件时,
mprep 和
mcc 实际上是产生一个包含明确调用
MathLink 库函数的 C 程序. 如果要理解
MathLink 库函数的工作过程,就可以查看这个程序的源代码. 注意,当使用
mcc 时,一般需要给出一个

选项,否则,所产生的源代码将会被自动删除.
当外部函数返回单个整数或浮点数时,可以在
MathLink 模板文件中对

给出
Integer 或者
Real. 但由于 C 中的内存分配和撤销方式,不能直接对

给出

或

等指定. 要返回这些结构时,必须在 C 程序中直接调用
MathLink 库函数,并对

指定
Manual.
这是一个函数的
MathLink 模板,该函数的变量是一个整数,直接用
MathLink 函数返回它的值.
:Begin:
:Function: bits
:Pattern: bits[i_Integer]
:Arguments: {i}
:ArgumentTypes: {Integer}
:ReturnType: Manual
:End:
这个函数被说明为一个空

函数.
void bits(int i) {
int a[32], k;
这里给 C 数组

赋值.
for(k=0; k<32; k++) {
a[k] = i%2;
i >>= 1;
if (i==0) break;
}
if (k<32) k++;
这里将数组

的

个元素送回到
Mathematica.
MLPutInteger32List(stdlink, a, k);
return ;
}
安装包含外部函数

的程序.
| Out[5]= |  |
| Out[6]= |  |
在 C 中用

说明一个数组时,可以用
MLPutInteger32Array() 将它作为一个深度为3的列表送入
Mathematica.
这里建立一个数组

,其初始值定义为

的维数.
int dims[] = {8, 16, 100};
将这个三维数组

送入
Mathematica 中,产生一个深度为 3 的列表.
MLPutInteger32Array(stdlink, a, dims, NULL, 3);
用
MathLink 函数完全能产生任何
Mathematica 表达式. 其基本思想是调用一系列直接与
Mathematica 表达式的
FullForm 表示对应的
MathLink 函数.
建立有两个变量的
Mathematica 函数
Plus.
MLPutFunction(stdlink, "Plus", 2);
指定第一个变量是整数

.
MLPutInteger32(stdlink, 77);
指定第二个变量是符号

.
MLPutSymbol(stdlink, "x");
一般地,先调用
MLPutFunction(),给出拟产生的
Mathematica 函数的头和所含变量的个数. 随后调用其它
MathLink 函数轮流填入每个变量.
"表达式" 节讨论了
Mathematica 表达式的一般结构和头的概念.
MLPutFunction(stdlink, "List", 2);
该列表的第一个元素是从 C 数组

中得到的 10 个整数的列表.
MLPutInteger32List(stdlink, r, 10);
MLPutFunction(stdlink, "List", 2);
MLPutReal64(stdlink, 4.5);
MLPutInteger32(stdlink, 11);
MLPutInteger32Array() 和
MLPutReal64Array() 可以输送由 C 预分配在内存中按一维形式存放的数组. 但在执行 C 程序过程中要产生数组时,通常将它们设置为指针的嵌套集合. 可以将这种数组送入
Mathematica,其方法是一系列
MLPutFunction() 调用和一个结束调用的
MLPutInteger32List().
这里说明

是一个整数数组的列表嵌套.
这里产生一个

个元素的
Mathematica 列表.
MLPutFunction(stdlink, "List", n1);
这里产生一个有

个元素的子列表.
MLPutFunction(stdlink, "List", n2);
MLPutInteger32List(stdlink, a[i][j], n3);
重要的一点是要知道,用
MathLink 函数产生的表达式当送入
Mathematica 后就立即计算. 例如,要对送到
Mathematica 的一个数组进行转置时,只需要将
Transpose 放在该数组表达式外即可. 为此,在产生表示这个数组的表达式之前要调用
MLPutFunction(stdlink, "Transpose", 1);.
送到
Mathematica 的后处理数据的思想有许多用途. 例如,它是输出事先不知道其长度的列表的途径.
通过直接追加相继元素在
Mathematica 中产生一个列表.
| Out[7]= |  |
| Out[8]= |  |
| Out[9]= |  |
| Out[10]= |  |
调用
MLPutInteger32List() 时要知道拟发送的列表长度. 但通过产生一个嵌套序列的
Sequence 对象后,就不需要事先知道整个列表的长度.
MLPutFunction(stdlink, "List", 1);
while( condition ) {
/* generate an element */
MLPutFunction(stdlink, "Sequence", 2);
MLPutInteger32(stdlink, i );
MLPutFunction(stdlink, "Sequence", 0);
直接从 Mathematica 得到数据的函数.
MathLink 提供的
MLPutInteger32() 等函数可以从外部程序向
Mathematica 发送数据.
MathLink 也提供了
MLGetInteger32() 等函数从
Mathematica 向外部程序发送数据.
MathLink 模板中对

给出的列表可以用
Manual 结束. 它表明当其它变量接收完后将调用
MathLink 函数去得到额外的表达式.
Mathematica 中的函数

有 3 个变量.
:Pattern: f[i_Integer, x_Real, y_Real]
:ArgumentTypes: {Integer, Manual}
这里对变量

和

进行说明.
MLGetReal64(stdlink, &x);
MLGetReal64(stdlink, &y);
MathLink 函数如
MLGetInteger32
等的工作过程类似于标准 C 库函数如

等. 第一个变量指定要得到数据的链接,最后一个变量给出数据应该存放的地址.
通过 MathLink 得到一个函数.
Mathematica 中的函数

的变量是一个整数列表.
:Pattern: f[a:{___Integer}]
:ReturnType: Integer
:End:
检查正被发送的函数是一个列表,和在

中存储了多少元素.
MLCheckFunction(stdlink, "List", &n);
得到列表中的每个元素将它存在

中.
for (i=0; i<n; i++)
MLGetInteger32(stdlink, a+i);
在简单情况下,在
Mathematica 这一方可以保证发送到外部程序的数据具有客观存在所需要的结构. 但仅当数据是由给定名称的函数时,
MLCheckFunction() 的返回值将是 MLSUCCESS.
注意,要得到嵌套列表集合或者其它对象时,可以调用适当的
MLCheckFunction()函数来实现.
获取数字列表.
外部程序从
Mathematica 得到数据后要安排它们的存放位置. 如果该数据像
MLGetInteger32
一样是单个整数,则用

对其进行说明即可.
但是当该数据可能是有任意长度的整数列表时,在实际调用外部程序时就要分配保存它的内存.
MLGetInteger32List
将自动地进行这种分配,并将
a 设置为结果的指针. 注意,
MLGetInteger32List() 等函数分配的内存总是放在一个特殊的区域中,不能直接修改或者释放它.
这里说明局部变量. 其中

是一个整数数组.
得到一个整数列表,将

作为结果指针.
MLGetInteger32List(stdlink, &a, &n);
MLReleaseInteger32List(stdlink, a, n);
由

指定

时,在外部函数退出时,
MathLink 将自动释放由该列表所占用的内存. 而用
MLGetInteger32List()直接得到一个整数列表时,与该列表有关的任务完成后用户不要忘记释放内存.
| MLGetInteger32Array(stdlink,int**a,int**dims,char***heads,int*d) |
| 得到任意深度的整数数组 |
| MLGetReal64Array(stdlink,double**a,int**dims,char***heads,int*d) |
| 得到任意深度的浮点数数组 |
| MLReleaseInteger32Array(stdlink,int*a,int*dims,char**heads,int d) |
| 释放与一个整数数组有关的内存 |
| MLReleaseReal64Array(stdlink,double*a,int*dims,char**heads,int d) |
| 释放与一个浮点数数组有关的内存 |
获取数字数组.
MLGetInteger32List() 从单个
Mathematica 列表得到一维整数数组.
MLGetInteger32Array() 从列表集合或具有任意深度的嵌套
Mathematica 函数得到一个整数数组.
在一个结构第
i 层的
Mathematica 函数名作为一个字符串存在

中. 第
i 层该结构的大小存在

中,而总深度存在
d 中.
向外部程序传递复数列表时,
MLGetReal64Array() 将产生一个二维数组,该数组是实部和虚部组成的序列. 此时,
heads[0] 将是
"List",而
heads[1] 将是

.
注意,可以与外部程序交换任意精度的数,其方法是用
IntegerDigits 和
RealDigits 在
Mathematica 中将它们转化为一个数字列表.
获取字符串和符号名.
在

指定中用
String 时,
MathLink 在函数撤销后将自动释放该字符串所占用的内存. 这意味着还要继续引用这个字符串时,就要对它分配内存,并将它所含的字符明确拷贝进去.
用
MLGetString()得到一个字符时,当函数退出时,
MathLink 将不会自动释放用于字符串的内存. 结果,用户可以继续引用这个字符串. 请注意不要因为写入
MLGetString()返回的内存,而修改字符串的内容. 当用户不再需要该字符串时,就要明确调用
MLReleaseString() 去释放与它有关的内存.
获取任意函数.
知道外部程序中需要的函数时,就可以简单地调用
MLCheckFunction(). 而不知道外部程序中需要的函数时,就只好调用
MLGetFunction(). 这样做时,就一定要调用
MLReleaseSymbol() 去释放与
MLGetFunction()所找出的函数的名称有关的内存.