虚拟全书 > 系统界面与部署 > MathLink 和外部程序的通讯 > 处理列表、数组和其它表达式 >

处理列表、数组和其它表达式

MathLink 可以与外部程序交换任何类型的数据. 对于更常用的数据类型,需要在 MathLink 模板文件中给出适当的 规格.
Mathematica 规定
C 规定
Integer整数int
Real浮点数double
IntegerList整数列表int*,long
RealList浮点数列表double*,long
String字符串char*
Symbol符号名char*
Manual直接调用 MathLink 子程序void

基本类型规定.

这里是一个函数的 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;
}
安装一个包含有函数 规定的外部程序.
In[1]:=
Click for copyable input
Out[1]=
这里调用外部代码.
In[2]:=
Click for copyable input
Out[2]=
这个与模式 不匹配,所有没有调用外部程序.
In[3]:=
Click for copyable input
Out[3]=
这里的模式是匹配的,但列表中的元素与外部代码中的类型不同,所以返回到 $Failed.
In[4]:=
Click for copyable input
Out[4]=
变量的这几种基本类型可以混合使用. 但使用 时,在 C 程序中必须包含一个额外的变量去代表该列表的长度.
这是一个 指定.
:ArgumentTypes:  {IntegerList, RealList, Integer}
这是可能对应的 C 函数陈述.
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 模板文件时,mprepmcc 实际上是产生一个包含明确调用 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 ;
}
安装包含外部函数 的程序.
In[5]:=
Click for copyable input
Out[5]=
这个外部函数返回一个位列表.
In[6]:=
Click for copyable input
Out[6]=
在 C 中用 说明一个数组时,可以用 MLPutInteger32Array() 将它作为一个深度为3的列表送入Mathematica.
说明三维的 C 数组.
   int a[8][16][100];
这里建立一个数组 ,其初始值定义为 的维数.
   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 表达式的一般结构和头的概念.
产生由两个元素的 Mathematica 列表.
MLPutFunction(stdlink, "List", 2);
该列表的第一个元素是从 C 数组 中得到的 10 个整数的列表.
MLPutInteger32List(stdlink, r, 10);
该列表的第2个元素本身是2个元素的列表.
MLPutFunction(stdlink, "List", 2);
这个子列表的第一个元素是一个浮点数.
MLPutReal64(stdlink, 4.5);
第二个元素是一个整数.
MLPutInteger32(stdlink, 11);
MLPutInteger32Array()MLPutReal64Array() 可以输送由 C 预分配在内存中按一维形式存放的数组. 但在执行 C 程序过程中要产生数组时,通常将它们设置为指针的嵌套集合. 可以将这种数组送入 Mathematica,其方法是一系列 MLPutFunction() 调用和一个结束调用的 MLPutInteger32List().
这里说明 是一个整数数组的列表嵌套.
int ***a;
这里产生一个 个元素的 Mathematica 列表.
MLPutFunction(stdlink, "List", n1);
for (i=0; i<n1; i++) {
这里产生一个有 个元素的子列表.
    MLPutFunction(stdlink, "List", n2);
    for (j=0; j<n2; j++) {
这里写出整数列表.
        MLPutInteger32List(stdlink, a[i][j], n3);
    }
}
重要的一点是要知道,用 MathLink 函数产生的表达式当送入 Mathematica 后就立即计算. 例如,要对送到Mathematica 的一个数组进行转置时,只需要将 Transpose 放在该数组表达式外即可. 为此,在产生表示这个数组的表达式之前要调用 MLPutFunction(stdlink, "Transpose", 1);.
送到 Mathematica 的后处理数据的思想有许多用途. 例如,它是输出事先不知道其长度的列表的途径.
通过直接追加相继元素在 Mathematica 中产生一个列表.
In[7]:=
Click for copyable input
Out[7]=
产生每个后继元素在一个嵌套子列表中的列表.
In[8]:=
Click for copyable input
Out[8]=
Flatten 压平了这个列表.
In[9]:=
Click for copyable input
Out[9]=
Sequence 自动压平了自己.
In[10]:=
Click for copyable input
Out[10]=
调用 MLPutInteger32List() 时要知道拟发送的列表长度. 但通过产生一个嵌套序列的 Sequence 对象后,就不需要事先知道整个列表的长度.
建立围绕结果的 List.
MLPutFunction(stdlink, "List", 1);
while( condition ) {
/* generate an element */
产生下一层的 Sequence 对象.
    MLPutFunction(stdlink, "Sequence", 2);
放入元素.
    MLPutInteger32(stdlink,  i );
}
关闭最后一个 Sequence 对象.
MLPutFunction(stdlink, "Sequence", 0);
MLGetInteger32(stdlink,int*i)得到一个整数,将其存放在地址
MLGetReal64(stdlink,double*x)得到一个浮点数,将它存放在地址

直接从 Mathematica 得到数据的函数.

MathLink 提供的 MLPutInteger32() 等函数可以从外部程序向 Mathematica 发送数据. MathLink 也提供了 MLGetInteger32() 等函数从 Mathematica 向外部程序发送数据.
MathLink 模板中对 给出的列表可以用 Manual 结束. 它表明当其它变量接收完后将调用MathLink 函数去得到额外的表达式.
:Begin:
:Function: f
Mathematica 中的函数 有 3 个变量.
:Pattern:        f[i_Integer, x_Real, y_Real]
这些变量全部直接传递给了外部程序.
:Arguments:      {i, x, y}
仅第一个变量直接传给了外部函数.
:ArgumentTypes:  {Integer, Manual}
:ReturnType:     Real
:End:
这个外部函数仅显含一个变量.
double f(int i) {
这里对变量 进行说明.
   double x, y;
MLGetReal64() 从链接直接得到数据.
   MLGetReal64(stdlink, &x);
MLGetReal64(stdlink, &y);
   return i+x+y;
}
MathLink 函数如 MLGetInteger32 等的工作过程类似于标准 C 库函数如 等. 第一个变量指定要得到数据的链接,最后一个变量给出数据应该存放的地址.
MLCheckFunction(stdlink,"name",int*n)
检查函数的头,保存它的变量数目

通过 MathLink 得到一个函数.

:Begin:
:Function: f
Mathematica 中的函数 的变量是一个整数列表.
:Pattern:        f[a:{___Integer}]
该列表直接传给了外部程序.
:Arguments:      {a}
外部程序重新手工地得到这些变量.
:ArgumentTypes:  {Manual}
:ReturnType:     Integer
:End:
该外部函数不显含变量.
int f(void) {
以下声明了局部变量.
    int n, i;
int a[MAX];
检查正被发送的函数是一个列表,和在 中存储了多少元素.
    MLCheckFunction(stdlink, "List", &n);
得到列表中的每个元素将它存在 中.
   for (i=0; i<n; i++)
MLGetInteger32(stdlink, a+i);
在简单情况下,在 Mathematica 这一方可以保证发送到外部程序的数据具有客观存在所需要的结构. 但仅当数据是由给定名称的函数时,MLCheckFunction() 的返回值将是 MLSUCCESS.
注意,要得到嵌套列表集合或者其它对象时,可以调用适当的 MLCheckFunction()函数来实现.
MLGetInteger32List(stdlink,int**a,int*n)
得到一个整数列表,分配存储它需要的内存
MLGetReal64List(stdlink,double**a,int*n)
得到一个浮点数列表
MLReleaseInteger32List(stdlink,int*a,int n)
释放与整数列表有关的内存
MLReleaseReal64List(stdlink,double*a,int n)
释放与浮点数列表有关的内存

获取数字列表.

外部程序从 Mathematica 得到数据后要安排它们的存放位置. 如果该数据像 MLGetInteger32 一样是单个整数,则用 对其进行说明即可.
但是当该数据可能是有任意长度的整数列表时,在实际调用外部程序时就要分配保存它的内存.
MLGetInteger32List 将自动地进行这种分配,并将 a 设置为结果的指针. 注意,MLGetInteger32List() 等函数分配的内存总是放在一个特殊的区域中,不能直接修改或者释放它.
这是一个发送整数列表的外部程序.
int f(void) {
这里说明局部变量. 其中 是一个整数数组.
    int n;
int *a;
得到一个整数列表,将 作为结果指针.
    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] 将是 .
注意,可以与外部程序交换任意精度的数,其方法是用 IntegerDigitsRealDigitsMathematica 中将它们转化为一个数字列表.
MLGetString(stdlink,char**s)得到一个字符串
MLGetSymbol(stdlink,char**s)得到一个符号名
MLReleaseString(stdlink,char*s)释放与一个字符串有关的内存
MLReleaseSymbol(stdlink,char*s)释放与一个符号有关的内存

获取字符串和符号名.

指定中用 String 时,MathLink 在函数撤销后将自动释放该字符串所占用的内存. 这意味着还要继续引用这个字符串时,就要对它分配内存,并将它所含的字符明确拷贝进去.
MLGetString()得到一个字符时,当函数退出时,MathLink 将不会自动释放用于字符串的内存. 结果,用户可以继续引用这个字符串. 请注意不要因为写入 MLGetString()返回的内存,而修改字符串的内容. 当用户不再需要该字符串时,就要明确调用 MLReleaseString() 去释放与它有关的内存.
MLGetFunction(stdlink,char**s,int*n)
开始获取一个函数,将它的头部名存在 s 中,变量个数存在 n
MLReleaseSymbol(stdlink,char*s)释放与函数名有关的内存

获取任意函数.

知道外部程序中需要的函数时,就可以简单地调用 MLCheckFunction(). 而不知道外部程序中需要的函数时,就只好调用MLGetFunction(). 这样做时,就一定要调用 MLReleaseSymbol() 去释放与 MLGetFunction()所找出的函数的名称有关的内存.
Ask a question about this page  |  Suggest an improvement  |  Leave a message for the team
格式:   HTML  |  CDF