perlxs-XS语言参考手册
XS是一种接口描述文件格式,用于在Perl和C代码(或C库)之间创建扩展接口,希望与Perl一起使用。XS接口与库相结合,创建一个新的库,然后可以动态加载或静态链接到perl中。XS接口描述是用XS语言编写的,是Perl扩展接口的核心组件。
安XSUB公司构成XS接口的基本单元。由xsubpp公司编译器,每个XSUB相当于一个C函数定义,它将在Perl调用约定和C调用约定之间提供粘合。
粘合代码从Perl堆栈中提取参数,将这些Perl值转换为C函数所需的格式,调用此C函数,将C函数的返回值传递回Perl。这里的返回值可以是传统的C返回值,也可以是作为输出参数的任何C函数参数。这些返回值可以通过将它们放在Perl堆栈上或通过修改Perl端提供的参数传递回Perl。
以上是对实际发生情况的一种简化看法。由于Perl允许比C更灵活的调用约定,XSUB在实践中可能做得更多,例如检查输入参数的有效性,如果C函数的返回值指示失败,则抛出异常(或返回undef/空列表),根据参数的数量和类型调用不同的C函数,提供面向对象的接口等。
当然,可以直接用C编写这样的粘合代码。然而,这将是一项繁琐的任务,尤其是如果需要为多个C函数编写粘合代码,和/或对Perl堆栈规程和其他类似的奥秘不够熟悉。XS在这里起到了拯救作用:人们可以写一个更简洁的短手代码,而不是用长手写这种粘合的C代码描述并让XS编译器xsubpp公司处理其余部分。
XS语言允许描述如何使用C例程和如何使用相应的Perl例程之间的映射。它还允许创建直接转换为C代码的Perl例程,这些例程与预先存在的C函数无关。在C接口与Perl接口一致的情况下,XSUB声明几乎与C函数的声明相同(K&R风格)。在这种情况下,还有另一种工具称为氢xs
它能够将整个C头文件转换为相应的XS文件,该XS文件将为头文件中描述的函数/宏提供粘合。
XS编译器被调用xsubpp公司此编译器创建了让XSUB操作Perl值所必需的构造,并创建了让Perl调用XSUB所必需的粘合。编译器使用类型图以确定如何将C函数参数和输出值映射到Perl值,然后再映射回来。默认的类型映射(Perl附带)处理许多常见的C类型。还可能需要一个补充的类型映射来处理所链接库的任何特殊结构和类型。
XS格式的文件以C语言部分开始,直到第一个模块=
指令。其他XS指令和XSUB定义可能遵循这一行。文件这一部分中使用的“语言”通常称为XS语言。xsubpp公司识别并跳过POD(请参阅珍珠贝)在C和XS语言部分中,这允许XS文件包含嵌入式文档。
请参见珀尔克斯图特获取有关整个扩展创建过程的教程。
注意:对于一些扩展,Dave Beazley的SWIG系统可能会为创建扩展粘合代码提供更方便的机制。请参见http://www.swig.org网站/了解更多信息。
#在路上
下面的许多示例将集中于创建Perl和ONC+RPC绑定库函数之间的接口。rpcb_gettime()函数用于演示XS语言的许多功能。此函数有两个参数;第一个是输入参数,第二个是输出参数。该函数还返回状态值。
bool_t rpcb_gettime(const char*host,time_t*timep);
从C开始,将使用以下语句调用此函数。
#包括<rpc/rpc.h>bool_t状态;time_t timep;状态=rpcb_gettime(“本地主机”,&timep);
如果创建一个XSUB来提供此函数和Perl之间的直接转换,那么将通过以下代码从Perl使用此XSUB。$status和$timep变量将包含函数的输出。
使用RPC;$status=rpcb_gettime(“本地主机”,$timep);
以下XS文件显示了一个XS子例程或XSUB,它演示了rpcb_gettime()函数的一个可能接口。这个XSUB表示C和Perl之间的直接转换,因此即使是从Perl也保留了接口。此XSUB将从Perl调用,用法如上所示。注意,前三个#include语句外部.h
,珀尔。小时
,以及XSUB。小时
,将始终出现在XS文件的开头。这一方法和其他方法将在本文件后面进行扩展。
#包括“EXTERN.h”#包括“perl.h”#包括“XSUB.h”#包括<rpc/rpc.h>模块=RPC包=RPCbool_t(布尔特)rpcb_gettime(主机,时间)char*主机time_t和timep输出:时间
任何对Perl的扩展,包括那些包含XSUB的扩展,都应该有一个Perl模块作为引导程序,将扩展拉入Perl。该模块将把扩展的函数和变量导出到Perl程序,并将扩展的XSUB链接到Perl。以下模块将用于本文档中的大多数示例,并且应该在Perl中与使用
命令,如前所示。Perl模块将在本文档后面进行更详细的解释。
包装RPC;要求出口商;需要DynaLoader;@ISA=qw(Exporter DynaLoader);@导出=qw(rpcb_gettime);引导RPC;1;
本文将探讨rpcb_gettime()XSUB的各种接口。XSUB将采用不同顺序的参数,或者采用不同数量的参数。在每种情况下,XSUB都是Perl和实际的C rpcb_gettime()函数之间的抽象,XSUB必须始终确保使用正确的参数调用实际的rpcb_get()函数。这个抽象将允许程序员为C函数创建一个更像Perl的接口。
#XSUB的剖析
最简单的XSUB由3部分组成:返回值的描述、XSUB例程的名称及其参数的名称,以及参数的类型或格式的描述。
下面的XSUB允许Perl程序访问名为sin()的C库函数。XSUB将模拟接受单个参数并返回单个值的C函数。
双重的罪(x)双倍x
或者,可以合并类型描述和参数名称列表,将其重写为
双重的sin(双x)
这使得XSUB看起来类似于ANSI C声明。参数列表后允许使用可选分号,如
双重的sin(双x);
具有C指针类型的参数可以具有不同的语义:具有类似声明的C函数
bool string_looks_a_number(字符*s);bool make_char_uppercase(char*c);
以完全不兼容的方式使用。可以描述这些功能的参数xsubpp公司这样地:
字符*s字符(&c)
这两个XS声明都对应于字符*
C类型,但它们有不同的语义,请参见“一元运算符(&U)”.
可以方便地认为间接操作符*
应视为类型和地址运算符的一部分&
应视为变量的一部分。请参见“类型图”有关在C类型中处理限定符和一元运算符的更多信息。
函数名和返回类型必须放在单独的行中,并应进行左对齐调整。
不正确正确双sin(x)双双x sin(x)双倍x
函数描述的其余部分可以缩进或向左调整。下面的示例显示了一个主体向左调整的函数。本文档中的大多数示例都会缩进正文以提高可读性。
对的双重的罪(x)双倍x
更复杂的XSUB可能包含许多其他部分。XSUB的每个部分都以相应的关键字开头,例如INIT:或CLEANUP:。然而,XSUB的前两行总是包含相同的数据:返回类型的描述、函数及其参数的名称。除非用另一个关键字显式标记,否则紧随其后的内容都被视为INPUT:节。(请参见“输入:关键字”.)
XSUB节将继续,直到找到另一个section-start关键字。
#参数堆栈
Perl参数堆栈用于存储作为参数发送给XSUB的值,以及存储XSUB返回值。实际上,所有Perl函数(包括非XSUB函数)都会同时在这个堆栈上保留其值,每个函数在堆栈上的位置都有自己的范围。在本文中,该堆栈上属于活动函数的第一个位置将被称为该函数的位置0。
XSUB使用宏引用其堆栈参数ST(x),其中x个指的是该XSUB的堆栈部分中的一个位置。XSUB将该函数的位置0称为ST(0)。XSUB的传入参数和传出返回值总是从ST(0)开始。对于许多简单的情况xsubpp公司编译器将通过嵌入类型映射中的代码片段来生成处理参数堆栈所需的代码。在更复杂的情况下,程序员必须提供代码。
#RETVAL变量
RETVAL变量是一个特殊的C变量,会自动为您声明。RETVAL的C类型与C库函数的返回类型相匹配。这个xsubpp公司编译器将在每个XSUB中使用非-空隙
返回类型。默认情况下,生成的C函数将使用RETVAL保存被调用的C库函数的返回值。在简单的情况下,RETVAL的值将放在参数堆栈的ST(0)中,Perl可以在其中接收它作为XSUB的返回值。
如果XSUB的返回类型为空隙
则编译器不会为该函数声明RETVAL变量。使用PPCODE:节时,不需要操作RETVAL变量,该节可以使用直接堆栈操作将输出值放置在堆栈上。
如果未使用PPCODE:指令,空隙
返回值应仅用于不返回值的子程序,即使CODE:使用了显式设置ST(0)的指令。
建议使用此文档的旧版本空隙
在这种情况下返回值。发现当XSUB真正地 空隙
。此做法现在已弃用,将来的某些版本可能不支持。使用返回值SV公司*
在这种情况下。(目前xsubpp公司
包含一些启发式代码,试图消除“true-void”和“old-practice-declared-as-void”函数之间的歧义。因此,除非您使用SV公司*
作为返回值。)
#MODULE关键字
MODULE关键字用于启动XS代码并指定正在定义的函数的包。第一个MODULE关键字之前的所有文本都被视为C代码,并被传递到输出中,POD被剥离,但在其他方面未被修改。每个XS模块都有一个引导函数,用于将XSUB挂接到Perl中。此引导程序函数的包名称将与XS源文件中最后一条MODULE语句的值匹配。MODULE的值在同一个XS文件中应该始终保持不变,尽管这不是必需的。
下面的示例将启动XS代码,并将所有函数放在名为RPC的包中。
模块=RPC
#PACKAGE关键字
当XS源文件中的函数必须分为包时,应使用PACKAGE关键字。此关键字与MODULE关键字一起使用,使用时必须紧跟其后。
模块=RPC包=RPC[RPC包中的XS代码]模块=RPC包=RPCB[包装RPCB中的XS代码]模块=RPC包=RPC[包RPC中的XS代码]
尽管此关键字是可选的,并且在某些情况下提供了冗余信息,但应始终使用它。此关键字将确保XSUB出现在所需的包中。
#PREFIX关键字
PREFIX关键字指定应从Perl函数名中删除的前缀。如果C函数是rpcb_gettime()
PREFIX值为rpcb公司_
然后Perl将此函数视为获取时间()
.
使用时,此关键字应跟随PACKAGE关键字。如果未使用PACKAGE,则前缀应跟随MODULE关键字。
模块=RPC前缀=RPC_模块=RPC包=RPCB前缀=RPCB_
#输出:关键字
关键字OUTPUT:表示当XSUB终止时,应该更新某些函数参数(新值对Perl可见),或者应该将某些值返回给调用Perl函数。对于没有CODE:或PPCODE:部分的简单函数,例如上面的sin()函数,RETVAL变量会自动指定为输出值。对于更复杂的函数xsubpp公司编译器需要帮助确定哪些变量是输出变量。
此关键字通常用于补充CODE:关键字。当存在CODE:关键字时,RETVAL变量不会被识别为输出变量。在这种情况下,使用OUTPUT:关键字告诉编译器RETVAL实际上是一个输出变量。
关键字OUTPUT:也可以用于指示函数参数是输出变量。当函数中的参数被修改并且程序员希望Perl看到更新时,这可能是必要的。
bool_t(布尔特)rpcb_gettime(主机,时间p)char*主机time_t和timep输出:时间
关键字OUTPUT:还允许将输出参数映射到匹配的代码段,而不是映射到类型映射。
bool_t(布尔特)rpcb_gettime(主机,时间p)char*主机time_t和timep输出:timep sv_setnv(ST(1),(双)timep);
xsubpp公司发出自动信号SvSETMAGIC()
对于XSUB的OUTPUT部分中的所有参数,RETVAL除外。这是通常需要的行为,因为它会正确调用输出参数上的“set”魔法(如果散列或数组元素参数不存在,则必须创建这些参数)。如果出于某种原因,不需要此行为,OUTPUT部分可能包含SETMAGIC:禁用
行以对OUTPUT部分中的其余参数禁用它。同样,SETMAGIC:启用
可以用于为OUTPUT部分的剩余部分重新启用它。请参见珍珠胶有关“设置”魔法的更多详细信息。
#NO_OUTPUT关键字
NO_OUTPUT可以作为XSUB的第一个标记。此关键字表示,虽然我们为C子例程提供的接口具有非-空隙
返回类型,则不应从生成的Perl子例程返回此C子例程的返回值。
存在此关键字“RETVAL变量”在生成的子程序调用中,此变量被赋值,但此变量的值不会在自动生成的代码中使用。
只有在以下情况下,此关键字才有意义RETVAL公司
将由用户提供的代码访问。使函数接口更像Perl尤其有用,尤其是当C返回值只是错误条件指示器时。例如,
NO_OUTPUT整数delete_file(字符*名称)拜访后:if(RETVAL!=0)嘎嘎声(“删除文件'%s'时出现错误%d”,RETVAL,名称);
在这里,生成的XS函数在成功时不返回任何结果,并在出错时显示一条有意义的错误消息()。
#代码:关键字
此关键字用于更复杂的XSUB,这些XSUB需要对C函数进行特殊处理。RETVAL变量仍被声明,但除非在OUTPUT:部分中指定,否则不会返回它。
以下XSUB适用于需要对其参数进行特殊处理的C函数。首先给出Perl的用法。
$status=rpcb_gettime(“localhost”,$timep);
接下来是XSUB。
bool_t(布尔特)rpcb_gettime(主机,时间)char*主机time_t时间代码:RETVAL=rpcb_gettime(主机,&timep);输出:时间RETVAL公司
#INIT:关键字
关键字INIT:允许在编译器生成对C函数的调用之前将初始化插入XSUB。与上面的CODE:关键字不同,此关键字不影响编译器处理RETVAL的方式。
布尔-trpcb_gettime(主机,时间)char*主机time_t和timep初始:printf(“#主机是%s\n”,主机);输出:时间
INIT:部分的另一个用途是在调用C函数之前检查先决条件:
长-长lldiv(a,b)long-long长a长-长b初始:如果(a==0&&b==0)XSRETURN_UNDEF;如果(b==0)沙哑(“lldiv:不能被0除”);
#NO_INIT关键字
NO_INIT关键字用于指示函数参数仅用作输出值。这个xsubpp公司编译器通常会生成代码,从参数堆栈中读取所有函数参数的值,并在进入函数时将其分配给C变量。NO_INIT将告诉编译器,某些参数将用于输出而不是输入,并且将在函数终止之前进行处理。
下面的示例显示rpcb_gettime()函数的变体。此函数仅将timep变量用作输出变量,不关心其初始内容。
bool_t(布尔特)rpcb_gettime(主机,时间)char*主机time_t&timep=无初始化输出:时间
#初始化函数参数
C函数参数通常使用参数堆栈中的值进行初始化(参数堆栈又包含从Perl传递到XSUB的参数)。类型映射包含用于将Perl值转换为C参数的代码段。然而,程序员可以覆盖类型映射并提供备用(或附加)初始化代码。初始化代码从第一个开始=
,;
或+
在INPUT:部分的一行上。唯一的例外是;
终止线路,然后这个;
被悄悄地忽略了。
下面的代码演示如何为函数参数提供初始化代码。在将初始化代码添加到输出之前,编译器会在双引号内对其进行求值,因此任何应该按字面意思解释的代码[主要是$
,@
,或\\
]必须用反斜线保护。变量$var、$arg和$type可以像在类型映射中一样使用。
bool_t(布尔特)rpcb_gettime(主机,时间)char*主机=(char*)SvPV($arg,PL_na);time_t&timep=0;输出:时间
这不应用于提供参数的默认值。当函数参数必须由另一个库函数处理后才能使用时,通常会使用此选项。下一节将介绍默认参数。
如果初始化开始于=
,然后在输入变量的声明中输出,替换类型映射提供的初始化。如果初始化开始于;
或+
,然后在声明所有输入变量后执行。在;
如果未执行类型映射通常提供的初始化。对于+
在这种情况下,变量的声明将包括来自类型映射的初始化。全局变量,%v(v)
适用于真正罕见的情况,即在另一个初始化中需要来自一个初始化的信息。
这里有一个真正晦涩难懂的例子:
bool_t(布尔特)rpcb_gettime(主机,时间)time_t&timep;/*\$v{timep}=@{[$v{timep}=$arg]}*/char*host+SvOK($v{timep})?SvPV($arg,PL_na):空;输出:时间
构造\$v{timep}=@{[$v{timep}=$arg]}
在上述示例中使用有两个目的:首先,当该行由xsubpp公司,Perl代码段$v{timep}=$arg
已评估。其次,计算的代码段的文本被输出到生成的C文件中(在C注释中)!在处理过程中char*主机
行,$arg的计算结果为ST(0)
,以及$v{timep}
将评估为ST(1)
.
#默认参数值
可以通过在参数列表中放置赋值语句来指定XSUB参数的默认值。默认值可以是数字、字符串或特殊字符串编号(_I)
。默认值应始终仅用于最右侧的参数。
为了允许rpcb_gettime()的XSUB具有默认主机值,可以重新排列XSUB的参数。然后,XSUB将使用正确顺序的参数调用实际的rpcb_gettime()函数。可以使用以下语句之一从Perl调用此XSUB:
$status=rpcb_gettime($timep,$host);$status=rpcb_gettime($timep);
XSUB看起来像下面的代码。代码:块用于调用实际的rpcb_gettime()函数,其中参数的顺序与该函数的正确顺序一致。
bool_t(布尔特)rpcb_gettime(timep,host=“localhost”)char*主机time_t timep=无信息代码:RETVAL=rpcb_gettime(主机,&timep);输出:时间RETVAL公司
#PREINIT:关键词
关键字PREINIT:允许在发出INPUT:部分中的参数声明之前或之后立即声明额外的变量。
如果在CODE:节中声明变量,它将跟随为输入参数发出的任何类型映射代码。这可能导致声明在C代码之后结束,这是C语法错误。类似的错误可能会发生在显式;
-类型或+
-使用参数的类型初始化(请参见“初始化函数参数”). 在INIT:部分中声明这些变量将没有帮助。
在这种情况下,要强制声明附加变量和其他变量的声明,请将声明放在PREINIT:节中。PREINIT:关键字可以在XSUB中使用一次或多次。
以下示例是等效的,但如果代码使用复杂的类型映射,那么第一个示例更安全。
bool_t(布尔特)rpcb_gettime(时间)time_t timep=无初始化前言:char*host=“localhost”;代码:RETVAL=rpcb_gettime(主机,&timep);输出:时间RETVAL公司
对于这种特殊情况,INIT:关键字将生成与PREINIT:关键字相同的C代码。另一个正确但容易出错的示例:
bool_t(布尔特)rpcb_gettime(时间p)time_t timep=无初始化代码:char*host=“localhost”;RETVAL=rpcb_gettime(主机,&timep);输出:时间重新估价
另一种申报方式主办
在CODE:部分中使用C块:
bool_t(布尔特)rpcb_gettime(时间)time_t timep=无初始化代码:{char*host=“localhost”;RETVAL=rpcb_gettime(主机,&timep);}输出:时间RETVAL公司
当类型映射转换操作某些全局状态时,在处理类型映射条目之前放置附加声明的功能非常方便:
我的对象变异前言:MyState st=全局状态;输入:我的对象o;清理:重置为(全局状态,st);
这里我们假设转换为我的对象
在INPUT:部分和处理RETVAL时从MyObject中修改全局变量全球状态
。执行这些转换后,我们将恢复旧值全球状态
(例如,为了避免内存泄漏)。
还有另一种方法以简洁换取清晰:INPUT部分允许声明C变量,这些变量不出现在子例程的参数列表中。因此,上述mutate()的代码可以重写为
我的对象变异MyState st=全局状态;我的对象o;清理:重置为(全局状态,st);
rpcb_gettime()的代码可以重写为
bool_t(布尔特)rpcb_gettime(时间p)time_t timep=无初始化char*host=“localhost”;ARGS(_ARGS):主机,&timep输出:时间RETVAL公司
#范围:关键词
关键字SCOPE:允许为特定XSUB启用作用域。如果启用,XSUB将自动调用ENTER和LEAVE。
为了支持潜在的复杂类型映射,如果XSUB使用的类型映射条目包含如下注释/*范围*/
然后将自动为该XSUB启用作用域。
要启用作用域:
范围:启用
要禁用作用域,请执行以下操作:
范围:禁用
XSUB的参数通常在进入XSUB后立即计算。可以使用INPUT:关键字强制稍后评估这些参数。关键字INPUT:可以在XSUB中多次使用,并且可以用于列出一个或多个输入变量。此关键字与PREINIT:关键字一起使用。
以下示例显示了输入参数如何时间
可以在PREINIT之后进行后期评估。
bool_t(布尔特)rpcb_gettime(主机,时间)char*主机前言:时间t tt;输入:time_t时间代码:RETVAL=rpcb_gettime(主机,&tt);时间p=tt;输出:时间重新估价
下一个示例显示了稍后评估的每个输入参数。
bool_t(布尔特)rpcb_gettime(主机,时间)前言:时间t tt;输入:char*主机前言:字符*h;输入:time_t时间代码:h=主机;RETVAL=rpcb_gettime(h,&tt);时间p=tt;输出:时间RETVAL公司
由于INPUT部分允许声明未出现在子程序参数列表中的C变量,因此可以缩写为:
bool_t(布尔特)rpcb_gettime(主机,时间)时间t tt;char*主机;char*h=主机;time_t timep;代码:RETVAL=rpcb_gettime(h,&tt);时间p=tt;输出:时间重新估价
(我们利用我们的知识字符*
是“简单”的,因此主办
在声明行上初始化,并且我们的赋值h=主机
没有过早执行。否则就需要分配h=主机
在CODE:或INIT:节中。)
#IN/OUTLIST/IN_OUTLIST/OUT/IN_OUT关键字
在XSUB的参数列表中,可以用英寸
/OUTLIST(输出列表)
/输入/输出列表
/OUT(输出)
/输入/输出
关键字。英寸
关键字是默认值,其他关键字指示Perl接口与C接口的区别。
前面的参数OUTLIST(输出列表)
/输入/输出列表
/输出
/输入/输出
关键字被认为是由C子程序使用的通过指针.OUTLIST(输出列表)
/OUT(输出)
关键字表示C子例程不检查该参数所指向的内存,而是通过该指针写入以提供其他返回值。
前面的参数OUTLIST(输出列表)
关键字不会出现在生成的Perl函数的使用签名中。
前面的参数输入/输出列表
/输入/输出
/OUT(输出)
做显示为Perl函数的参数。除了OUT(输出)
-参数,这些参数被转换为相应的C类型,然后指向这些数据的指针作为C函数的参数。预计C函数将通过这些指针进行写入。
生成的Perl函数的返回列表由函数的C返回值组成(除非XSUB是空隙
返回类型或NO_OUTPUT关键字
使用),然后是所有OUTLIST(输出列表)
和输入/输出列表
参数(按出现的顺序)。从XSUB返回时输入/输出
/OUT(输出)
Perl参数将被修改为由C函数写入值。
例如,XSUB
空隙day_month(OUTLIST天,IN unix_time,OUTLIST-month)int天int unix时间int个月
应在Perl中用作
my($day,$month)=日_月(time);
相应函数的C签名应为
void day_month(int*day,intunix_time,int*month);
这个英寸
/寿命最长的
/输入/输出列表
/输入/输出
/OUT(输出)
关键字可以与ANSI样式声明混合,如
空隙day_month(OUTLIST int day,int unix_time,OUTLIST-int month)
(这里是可选的英寸
关键字被省略)。
这个输入/输出
参数与引入的参数相同“一元运算符(&U)”并将其放入输出:
部分(请参见“输出:关键字”). 这个输入/输出列表
参数非常相似,唯一的区别是C函数通过指针写入的值不会修改Perl参数,而是放在输出列表中。
这个寿命最长的
/OUT(输出)
参数不同于输入/输出列表
/输入/输出
参数仅由未被读取的Perl参数的初始值决定(并且未被赋予C函数-它会得到一些垃圾)。例如,与上述相同的C函数可以作为
void day_month(OUT int day,int unix_time,OUT int month);
或
空隙day_month(日,unix_time,月)int&day=NO_INITint unix时间int&month=NO_INIT输出:白天月
然而,生成的Perl函数是以非常C-ish的方式调用的:
我的($day,$month);day_month($day,time,$month);
#可变长度参数列表
XSUB可以通过指定省略号来拥有可变长度的参数列表(...)
在参数列表中。省略号的这种用法类似于ANSI C中的省略号。程序员可以通过检查项目
变量,其中xsubpp公司编译器为所有XSUB提供。通过使用此机制,可以创建一个XSUB,它接受未知长度的参数列表。
这个主办rpcb_gettime()XSUB的参数可以是可选的,因此可以使用省略号来指示XSUB将接受数量可变的参数。Perl应该能够使用以下语句调用此XSUB。
$status=rpcb_gettime($timep,$host);$status=rpcb_gettime($timep);
下面是带有省略号的XS代码。
bool_t(布尔特)rpcb_gettime(时间,…)time_t timep=无初始化前言:char*host=“localhost”;斯特林(_a);代码:if(项>1)主机=(char*)SvPV(ST(1),n_a);RETVAL=rpcb_gettime(主机,&timep);输出:时间RETVAL公司
#C_ARGS:关键字
C_ARGS:关键字允许创建XSUBS,它在Perl中的调用顺序与在C中的调用序列不同,而无需编写CODE:或PPCODE:节。C_ARGS:paragraph的内容作为被调用C函数的参数,没有任何更改。
例如,假设一个C函数被声明为
符号nth_divative(int n,符号函数,int标志);
默认标志保存在全局C变量中默认标志(_F)
。假设您要创建一个称为
$second_deriv=$function->nth_derivative(2);
为此,将XSUB声明为
象征的第n个导数(函数,n)符号函数整数nARGS(_ARGS):n、 函数,default_flags
#PPCODE:关键字
PPCODE:关键字是CODE:关键字的另一种形式,用于告诉xsubpp公司编译器,程序员提供代码来控制XSUB返回值的参数堆栈。有时人们会希望XSUB返回值列表,而不是单个值。在这些情况下,必须使用PPCODE:,然后显式推送堆栈上的值列表。PPCODE:和CODE:关键字不应在同一XSUB中一起使用。
PPCODE:和CODE:部分之间的实际差异在于初始化服务提供商
宏(表示现在的Perl堆栈指针),并在从XSUB返回时处理堆栈上的数据。在CODE:段中,SP保留XSUB入口的值:SP位于函数指针上(紧跟在最后一个参数之后)。在PPCODE中:部分SP向后移动到参数列表的开头,这允许推*()
当XSUB返回到Perl时,宏将输出值放置在Perl期望的位置。
为CODE:部分生成的尾部确保Perl将看到的返回值的数量为0或1(取决于空隙
C函数返回值的性质,以及中提到的启发式“RETVAL变量”). 为PPCODE:部分生成的尾部基于返回值的数量和次数服务提供商
由更新[十] 推*()
宏。
请注意,宏ST(i)
,XST_m*()
和XSRETURN*()
在CODE:sections和PPCODE:sections中同样出色。
下面的XSUB将调用C rpcb_gettime()函数,并将其两个输出值timep和status作为一个列表返回给Perl。
空隙rpcb_gettime(主机)char*主机前言:time_t timep;bool_t状态;PP代码:状态=rpcb_gettime(主机,&timep);延伸(SP,2);PUSH(sv_2致命(新SViv(状态)));PUSH(sv_2manual(newSViv(timep)));
请注意,程序员必须提供调用真正的rpcb_gettime()函数以及将返回值正确放置在参数堆栈上所必需的C代码。
这个空隙
此函数的返回类型告诉xsubpp公司编译器,不需要或不使用RETVAL变量,并且不应创建它。在大多数情况下,void返回类型应与PPCODE:指令一起使用。
EXTEND()宏用于在参数堆栈上为2个返回值腾出空间。PPCODE:指令导致xsubpp公司编译器创建可用的堆栈指针服务提供商
,并且该指针正在EXTEND()宏中使用。然后使用PUSHs()宏将值推送到堆栈上。
现在,可以通过以下语句从Perl中使用rpcb_gettime()函数。
($status,$timep)=rpcb_gettime(“本地主机”);
使用PPCODE节处理输出参数时,请确保正确处理“设置”魔法。请参见珍珠胶有关“设置”魔法的详细信息。
#返回取消定义和空列表
有时程序员会想简单地返回未定义
如果函数失败,则为空列表,而不是单独的状态值。rpcb_gettime()函数正好提供了这种情况。如果函数成功,我们希望它返回时间,如果失败,我们希望返回undef。在下面的Perl代码中,$timep的值要么是undef,要么是有效时间。
$timep=rpcb_gettime(“本地主机”);
以下XSUB使用SV公司*
返回类型仅作为助记符,并使用CODE:块向编译器指示程序员已提供了所有必要的代码。sv_newmotal()调用将把返回值初始化为undef,使其成为默认返回值。
蒸汽发生器*rpcb_gettime(主机)char*主机前言:time_t timep;bool_t x;代码:ST(0)=sv_newmotal();if(rpcbgettime(主机,&timep))sv_setnv(ST(0),(双)timep);
下一个示例演示了如果需要,如何在返回值中放置显式undef。
SV公司*rpcb_gettime(主机)char*主机预安装:time_t timep;bool_t x;代码:ST(0)=sv_newmotal();if(rpcbgettime(主机,&timep)){sv_setnv(ST(0),(双)timep);}其他{ST(0)=&PL_sv_undef;}
要返回空列表,必须使用PPCODE:块,然后不要将返回值推送到堆栈上。
空隙rpcb_gettime(主机)char*主机前言:time_t timep;PP代码:if(rpcbgettime(主机,&timep))PUSH(sv_2manual(newSViv(timep)));其他{/*堆栈上没有任何内容,因此为空*列表是隐式返回的*/}
有些人可能倾向于包含一个明确的返回
在上面的XSUB中,而不是让控制权落到最后。在这些情况下XSRETURN_EMPTY(返回_ MPTY)
应该使用。这将确保正确调整XSUB堆栈。咨询perlguts中的“API LISTING”对于其他XSRETURN(返回)
宏。
自XSRETURN(返回)_*
宏也可以与CODE块一起使用,可以将此示例重写为:
整数rpcb_gettime(主机)char*主机前言:time_t timep;代码:RETVAL=rpcb_gettime(主机,&timep);如果(RETVAL==0)XSRETURN_UNDEF;输出:重新估价
事实上,也可以将此检查放入POST_CALL:部分。再加上PREINIT:简化,这将导致:
整数rpcb_gettime(主机)char*主机time_t timep;拜访后:如果(RETVAL==0)XSRETURN_UNDEF;
#要求:关键字
REQUIRE:关键字用于指示xsubpp公司编译器需要编译XS模块。包含以下语句的XS模块将只使用xsubpp公司1.922或更高版本:
要求:1.922
#清洁:关键词
当XSUB在终止之前需要特殊的清理过程时,可以使用此关键字。当使用CLEANUP:关键字时,它必须位于XSUB中存在的任何CODE:、PPCODE:或OUTPUT:块之后。为清理块指定的代码将作为XSUB中的最后一条语句添加。
#POST_CALL:关键字
当XSUB需要在执行C子例程调用后执行特殊过程时,可以使用此关键字。当使用POST_CALL:关键字时,它必须位于XSUB中存在的OUTPUT:和CLEANUP:块之前。
当用户通过提供CODE:或PPCODE:部分来提供C子例程调用时,POST_CALL:块没有多大意义。
#BOOT:关键词
关键字用于向扩展的引导程序函数添加代码。引导程序函数由xsubpp公司编译器,通常保存用Perl注册任何XSUB所需的语句。使用BOOT:关键字,程序员可以告诉编译器向引导函数添加额外的语句。
此关键字可以在第一个MODULE关键字之后的任何时间使用,并且应该单独出现在一行上。关键字后的第一个空行将终止代码块。
启动:#当#执行引导程序函数。printf(“您好,来自引导程序!\n”);
#VERSIONCHECK:关键字
VERSIONCHECK:关键字对应于xsubpp公司的-版本检查
和-小说检查
选项。此关键字将覆盖命令行选项。默认情况下启用版本检查。启用版本检查后,XS模块将尝试验证其版本是否与PM模块的版本匹配。
要启用版本检查,请执行以下操作:
版本检查:启用
要禁用版本检查,请执行以下操作:
版本检查:禁用
#原型:关键字
PROTOTYPES:关键字对应于xsubpp公司的-原型
和-无原型
选项。此关键字将覆盖命令行选项。默认情况下启用原型。启用原型后,XSUB将获得Perl原型。此关键字可以在XS模块中多次使用,以启用和禁用模块不同部分的原型。
要启用原型,请执行以下操作:
原型:启用
要禁用原型:
原型:禁用
#原型:关键字
此关键字与上面的PROTOTYPES:关键字类似,但可以用于强制xsubpp公司为XSUB使用特定的原型。此关键字覆盖所有其他原型选项和关键字,但仅影响当前XSUB。咨询perlsub中的“原型”有关Perl原型的信息。
bool_t(布尔特)rpcb_gettime(时间,…)time_t timep=无初始化原型:$$前言:char*host=“localhost”;斯特林(_a);代码:if(项>1)主机=(char*)SvPV(ST(1),n_a);RETVAL=rpcb_gettime(主机,&timep);输出:时间RETVAL公司
#ALIAS:关键词
关键字ALIAS:允许XSUB有两个或多个唯一的Perl名称,并知道调用时使用了哪些名称。Perl名称可以完全限定为包名称。每个别名都有一个索引。编译器将设置一个名为九
其中包含使用的别名的索引。使用声明的名称调用XSUB时九
将为0。
以下示例将创建别名FOO::gettime()
和酒吧::getit()
用于此函数。
bool_t(布尔特)rpcb_gettime(主机,时间)char*主机时间(&t)别名:FOO::gettime=1条形图::getit=2初始:printf(“#ix=%d\n”,ix);输出:时间
#界面:关键词
此关键字将当前XSUB声明为给定调用签名的守护者。如果此关键字后面有一些文本,则将其视为具有此签名的函数列表,并应附加到当前XSUB。
例如,如果有4个C函数multiply()、divide()、add()和subtract(),它们都有签名:
符号f(符号,符号);
您可以使用以下命令使它们都使用相同的XSUB:
象征的接口(arg1、arg2)符号arg1符号arg2接口:乘除加减
(这是4个Perl函数的完整XSUB代码!)四个生成的Perl函数与相应的C函数共享名称。
与ALIAS:关键字相比,这种方法的优点是不需要编写switch语句,每个Perl函数(共享相同的XSUB)都知道应该调用哪个C函数。此外,可以在运行时使用以下命令附加额外的函数remainder()
CV*mycv=newXSproto(“符号::剩余”,XS_Symbolic_interface_s_ss,__FILE__,“$$”);XSINTERFACE_FUNC_SET(mycv,余数);
比如,从另一个XSUB。(本例假设没有INTERFACE_MACRO:节,否则需要使用其他内容,而不是XSINTERFACE_FUNC_SET(XS接口_功能_设置)
,请参阅下一节。)
#INTERFACE_MACRO:关键词
此关键字允许使用不同的方法定义INTERFACE,以从XSUB提取函数指针。该关键字后面的文本应给出宏的名称,该宏将提取/设置函数指针。提取器宏为返回类型,简历*
,以及XSANY.any_dptr公司
为了这个简历*
。setter宏被赋予cv和函数指针。
默认值为XS接口_FUNC
和XSINTERFACE_FUNC_SET(XS接口_功能_设置)
。如果使用INTERFACE_MACRO关键字,则可以省略函数列表为空的INTERFACE关键字。
假设在前面的示例函数中,multiply()、divide()、add()和subtract()的指针保存在一个全局C数组中fp[]
偏移为乘数(multiply _off)
,分隔(_O)
,添加_关闭
,减_关
。然后可以使用
#定义XSINTERFACE_FUNC_BYOFFSET(ret,cv,f)\(((XSINTERFACE_CVT(ret,))fp[CvXSUBANY(cv).any_i32])#定义XSINTERFACE_FUNC_BYOFFSET_set(cv,f)\CvXSUBANY(cv).any_i32=类别2(f,_off)
在C段中,
象征的接口(arg1、arg2)符号arg1符号arg2接口_MACRO:XSINTERFACE_FUNC_BYOFFSET接口XSINTERFACE_FUNC_BYOFFSET设置接口:乘除加减
在XSUB部分中。
#INCLUDE:关键字
此关键字可用于将其他文件拉入XS模块。其他文件可能包含XS代码。INCLUDE:也可以用来运行一个命令来生成要拉入模块的XS代码。
文件卢比1.xsh包含我们的rpcb_gettime()
功能:
bool_t(布尔特)rpcb_gettime(主机,时间)char*主机time_t和timep输出:时间
XS模块可以使用INCLUDE:将该文件拉入其中。
包括:Rpcb1.xsh
如果INCLUDE:关键字的参数后面跟管道(|
)然后编译器将参数解释为命令。
包括:猫Rpcb1.xsh|
#案例:关键词
CASE:关键字允许XSUB具有多个不同的部分,每个部分充当一个虚拟XSUB。CASE:是贪婪的,如果使用它,则所有其他XS关键字必须包含在CASE:中。这意味着在XSUB中,第一个CASE:之前可能没有任何内容,最后一个CASE:之后的任何内容都包含在该案例中。
CASE:可以通过XSUB的参数,通过九
ALIAS:变量(请参阅“ALIAS:关键词”),或者可能通过项目
变量(请参见“可变长度参数列表”). 最后一个案例:成为违约如果它与条件无关,则为case。以下示例显示CASE通过九
带有函数rpcb_gettime()
有别名x_gettime()
。当函数被调用为rpcb_gettime()
它的参数是通常的(char*主机,time_t*timep)
,但当函数被调用为x_获取时间()
参数颠倒,(time_t*timep,char*host)
.
长的rpcb获取时间(a,b)案例:ix==1别名:x_gettime=1输入:#“a”是timep,“b”是host字符*btime_t a=无初始化代码:RETVAL=rpcb_gettime(b,&a);输出:一RETVAL公司案例:#“a”是主机,“b”是时间字符*atime_t&b=无初始化输出:bRETVAL公司
可以使用以下语句调用该函数。注意不同的参数列表。
$status=rpcb_gettime($host,$timep);$status=x_gettime($timep,$host);
#一元运算符(&U)
这个&
INPUT:部分中的一元运算符用于告诉xsubpp公司它应该使用左边的C类型将Perl值转换为C或从C转换&
,但在调用C函数时提供指向此值的指针。
对于通过引用获取参数的C函数,这有助于避免出现CODE:块。通常,参数不应是指针类型(整数
或长的
但不是整数*
或长*
).
以下XSUB将生成错误的C代码。这个xsubpp公司编译器会将其转换为调用rpcb_gettime()
带参数(char*主机,time_t timep)
,但真实的rpcb_gettime()
想要时间
参数的类型时间_t*
而不是time_t(时间)
.
bool_t(布尔特)rpcb_gettime(主机,时间)char*主机time_t时间输出:时间
通过使用&
操作员。这个xsubpp公司编译器现在将其转换为调用rpcb_gettime()
正确使用参数(char*主机,time_t*timep)
。它通过携带&
通过,所以函数调用看起来像rpcb_gettime(主机,&timep)
.
bool_t(布尔特)rpcb_gettime(主机,时间)char*主机time_t和timep输出:时间
允许在BOOT:、PREINIT:INIT:、CODE:、PPCODE:,POST_CALL:和CLEANUP:块内以及函数外使用C预处理器指令。允许在MODULE关键字之后的任何位置添加注释。编译器将原封不动地传递预处理器指令,并删除注释行。在C和XS语言部分中,任何时候都允许使用POD文档。POD必须以=切割
命令;xsubpp公司
否则将退出并返回错误。人工生成的C代码不太可能被误认为POD,因为大多数缩进样式都会在以=
。计算机生成的XS文件可能会落入此陷阱,除非注意确保空格打断序列“\n=”。
可以通过放置#
作为行的第一个非空白。应注意避免使注释看起来像C预处理器指令,以免被解释为C预处理器指示。防止这种情况发生的最简单方法是在#
.
如果使用预处理器指令选择函数的两个版本之一,请使用
#如果。。。版本1#其他/*。。。版本2*/#结尾
而不是
#如果。。。版本1#结尾#如果。。。版本2#结尾
因为不然xsubpp公司会相信你对函数做了重复的定义。此外,在#else/#endif之前放一个空行,这样它就不会被视为函数体的一部分。
#将XS与C一起使用++
如果XSUB名称包含::
,它被认为是一种C++方法。生成的Perl函数将假定其第一个参数是对象指针。对象指针将存储在名为THIS的变量中。该对象应该是由C++使用new()函数创建的,并且应该是由Perl使用sv_setref_pv()宏创建的。Perl对对象的祝福可以通过类型映射来处理。本节末尾显示了一个类型图示例。
如果XSUB的返回类型包括静止的
,该方法被视为静态方法。它将使用class::method()语法调用C++函数。如果该方法不是静态的,则将使用THIS->method()语法调用该函数。
接下来的示例将使用以下C++类。
类颜色{公众:颜色();~颜色();int蓝色();无效set_blue(int);私人:int c_blue;};
blue()和set_blue()方法的XSUB是用类名定义的,但对象的参数(THIS或“self”)是隐式的,未列出。
整数颜色::蓝色()空隙颜色::set_blue(val)整数val
这两个Perl函数都需要一个对象作为第一个参数。在生成的C++代码中,对象被调用这个
,将对此对象执行方法调用。因此,在C++代码中,blue()和set_blue(
RETVAL=此->蓝色();此->设置蓝色(val);
您还可以使用可选参数编写单个get/set方法:
整数颜色::蓝色(val=NO_INIT)整数val原型$$代码:if(项>1)此->设置蓝色(val);RETVAL=此->蓝色();输出:重新估价
如果函数名为毁灭然后是C++删除
函数将被调用,并且这个
将作为其参数给出。为生成的C++代码
空隙颜色::DESTROY()
将如下所示:
color*THIS=。。。;//初始化为类型映射删除THIS;
如果函数名为新的然后是C++新的
函数将被调用以创建动态C++对象。XSUB需要类名,类名将保存在名为类别
,作为第一个参数。
颜色*颜色::new()
生成的C++代码将调用新的
.
RETVAL=新颜色();
下面是可用于此C++示例的类型映射示例。
TYPEMAP(类型图)颜色*O_OBJECT输出#Perl对象被命名为“CLASS”,它应该是一个#有祝福包裹的名字。对象(_O)sv_setref_pv($arg,类,(void*)$var);INPUT(输入)对象(_O)if(sv_isobject($arg)&&(SvTYPE(SvRV($ag))==SVt_PVMG))$var=($type)SvIV((SV*)SvRV($arg));其他{警告(“${Package}::$func_name()--$var不是受祝福的SV引用”);XSRETURN_UNDEF;}
#接口策略
在设计Perl和C库之间的接口时,需要将C直接转换为XS(例如由h2xs-x型
)通常就足够了。然而,有时接口看起来非常像C,有时是非直觉的,尤其是当C函数修改其参数之一,或在带内返回失败时(如“负返回值意味着失败”)。在程序员希望创建更像Perl的接口的情况下,以下策略可能有助于识别接口中更关键的部分。
使用输入/输出或输出参数识别C功能。这些函数的XSUB可以将列表返回给Perl。
识别使用一些带内信息作为故障指示的C功能。它们可能是在失败时返回undef或空列表的候选项。如果在不调用C函数的情况下检测到故障,您可能需要使用INIT:部分来报告故障。对于C函数返回后可检测到的故障,可能需要使用POST_CALL:节来处理故障。在更复杂的情况下,使用CODE:或PPCODE:节。
如果许多函数基于返回值使用相同的失败指示,您可能需要创建一个特殊的typedef来处理这种情况。放置
typedef int negative_is_failure;
在XS文件开头附近,并为创建OUTPUT类型映射条目否定是失败
将负值转换为未定义
,或者可能是croak()s。在此之后,类型的返回值否定是失败
将创建更多类似Perl的接口。
确定哪些值仅由C和XSUB函数本身使用,例如,当函数的参数应该是全局变量的内容时。如果Perl不需要访问值的内容,那么可能不需要为该值提供从C到Perl的转换。
识别C函数参数列表中的指针和返回值。一些指针可以用来实现输入/输出或输出参数,它们可以在XS中用&
一元运算符,并且可能使用NO_INIT关键字。其他一些则需要处理以下类型整数*
在这种情况下,需要决定一个有用的Perl翻译会做什么。当语义明确时,建议将译文放入类型映射文件中。
识别C函数使用的结构。在许多情况下,为这些结构使用T_PTROBJ类型映射可能会有所帮助,以便Perl可以将它们作为受祝福的对象进行操作。(这由自动处理h2xs-x型
.)
如果在需要不同翻译的几个不同上下文中使用相同的C类型,类型定义
映射到此C类型的几个新类型,并创建单独的类型图这些新类型的条目。在XSUB的返回类型和参数声明中使用这些类型。
#Perl对象和C结构
在处理C结构时,应该选择其中之一T_PTROBJ或T_PTRREF(_PTRREF)用于XS类型。这两种类型都设计用于处理指向复杂对象的指针。T_PTRREF类型将允许取消对Perl对象的访问,而T_PTROBJ类型要求对该对象进行访问。通过使用T_PTROBJ,可以实现一种类型检查形式,因为XSUB将尝试验证Perl对象是否为预期类型。
以下XS代码显示了与ONC+TIRPC一起使用的getnetconfigent()函数。getnetconfigent()函数将返回一个指向C结构的指针,并具有如下所示的C原型。该示例将演示C指针如何成为Perl引用。Perl会将此引用视为指向受祝福对象的指针,并尝试为该对象调用析构函数。XS源代码中将提供析构函数来释放getnetconfigent()使用的内存。XS中的析构函数可以通过指定名称以单词结尾的XSUB函数来创建毁灭.XS析构函数可用于释放可能被另一个XSUB分配的内存。
struct netconfig*getnetconfigent(常量字符*netid);
A类类型定义
将为创建结构netconfig
。Perl对象将在一个与C类型的名称匹配的类中得到祝福,该类带有标记Ptr公司
如果名称是Perl包名称,则该名称不应包含嵌入空格。析构函数将被放置在与对象类相对应的类中,PREFIX关键字将被用于按照Perl的预期将名称修饰为单词DESTROY。
typedef结构netconfig netconfig;模块=RPC包=RPCNetconfig(网络配置)*获取网络配置(netid)字符*netid模块=RPC包=NetconfigPtr前缀=rpcb_空隙rpcb_DESTROY(网络连接)Netconfig*netconf代码:printf(“现在在NetconfigPtr::DESTROY\n”);免费(netconf);
此示例需要以下类型映射条目。有关为扩展添加新类型映射的更多信息,请参阅类型映射部分。
TYPEMAP(类型图)网络配置*T_PTROBJ
此示例将与以下Perl语句一起使用。
使用RPC;$netconf=getnetconfigent(“udp”);
当Perl销毁$netconf引用的对象时,它会将该对象发送到提供的XSUB DESTROY函数。Perl无法确定,也不关心这个对象是否是C结构,而不是Perl对象。从这个意义上讲,getnetconfigent()XSUB创建的对象与普通Perl子例程创建的对象没有区别。
#类型图
类型映射是由xsubpp公司编译器将C函数参数和值映射到Perl值。类型映射文件可能包含三个标有TYPEMAP(类型图)
,INPUT(输入)
,以及输出
。未标记的初始截面假定为TYPEMAP(类型图)
第节。INPUT部分告诉编译器如何将Perl值转换为特定C类型的变量。OUTPUT部分告诉编译器如何将某些C类型的值转换为Perl可以理解的值。TYPEMAP部分告诉编译器应该使用哪个INPUT和OUTPUT代码片段将给定的C类型映射为Perl值。横断面标签类型映射
,INPUT(输入)
,或输出
必须从一行的第一列开始,并且必须大写。
中的默认类型映射库/外部实用程序
Perl源代码的目录包含许多有用的类型,Perl扩展可以使用这些类型。一些扩展定义了附加的类型映射,并将其保存在自己的目录中。这些附加类型映射可以引用主类型映射中的INPUT和OUTPUT映射。这个xsubpp公司编译器将允许扩展自己的类型映射覆盖默认类型映射中的任何映射。
大多数需要自定义类型映射的扩展只需要类型映射文件的typemap部分。前面显示的getnetconfigent()示例中使用的自定义类型映射演示了扩展类型映射的典型用法。该类型映射用于将C结构等同于T_PTROBJ类型映射。此处显示了getnetconfigent()使用的类型映射。注意,C类型与XS类型用制表符分开,C一元运算符*
被视为C类型名称的一部分。
TYPEMAP(类型图)Netconfig*<tab>T_PTROBJ
这里有一个更复杂的例子:假设你想要结构netconfig
被祝福进入课堂网络::配置
。一种方法是使用下划线(_)分隔包名称,如下所示:
typedef结构netconfig*Net_Config;
然后提供类型映射条目T_PTROBJ_特殊
将下划线映射为双冒号(::)并声明网络配置(_C)
属于该类型:
TYPEMAP类型网络配置T_PTROBJ_SPECIALINPUT(输入)T_PTROBJ_特殊if(sv_derived_from($arg,\“${(我的$ntt=$ntype)=~s/_/::/g;\$ntt}\”){IV tmp=SvIV((SV*)SvRV($arg));$var=($type)tmp;}其他的croak(“$var不是${(my$ntt=$ntype)=~s/_/::/g;\$ntt}类型”)输出T_PTROBJ_特殊sv_setref_pv($arg,\“${(my$ntt=$ntype)=~s/_/:/g;\$ntt}\”,(无效*)$var);
INPUT和OUTPUT部分动态地将下划线替换为双冒号,从而获得所需的效果。这个例子展示了类型映射工具的一些功能和多功能性。
文件RPC.xs公司
:某些ONC+RPC绑定库函数的接口。
#包括“EXTERN.h”#包括“perl.h”#包括“XSUB.h”#包括<rpc/rpc.h>typedef结构netconfig netconfig;模块=RPC包=RPCSV公司*rpcb_gettime(主机=“localhost”)char*主机前言:time_t timep;代码:ST(0)=sv_newmotal();if(rpcbgettime(主机,&timep))sv_setnv(ST(0),(双)timep);网络配置*getnetconfigent(netid=“udp”)字符*netid模块=RPC包=NetconfigPtr前缀=rpcb_空隙rpcb_DESTROY(网络连接)Netconfig*netconf代码:printf(“NetconfigPtr::DESTROY\n”);免费(netconf);
文件类型图
:RPC.xs的自定义类型映射。
TYPEMAP(类型图)网络配置*T_PTROBJ
文件RPC.下午
:RPC扩展的Perl模块。
包装RPC;要求出口商;需要DynaLoader;@ISA=qw(Exporter DynaLoader);@导出=qw(rpcb_gettime getnetconfigent);引导RPC;1;
文件快速测试.pl
:RPC扩展的Perl测试程序。
使用RPC;$netconf=getnetconfig();$a=rpcb_gettime();打印“time=$a\n”;打印“netconf=$netconf\n”;$netconf=getnetconfigent(“tcp”);$a=rpcb_gettime(“杨树”);打印“time=$a\n”;打印“netconf=$netconf\n”;
#XS版本
本文档涵盖支持的功能xsubpp公司
1.935.
最初由Dean Roehrich撰写<roehrich@cray.com>.
自1996年起由Perl Porters维护<perlbug@perl.org>.