这是命令 perlxstypemap,可以使用我们的多个免费在线工作站之一在 OnWorks 免费托管服务提供商中运行,例如 Ubuntu Online、Fedora Online、Windows 在线模拟器或 MAC OS 在线模拟器
程序:
您的姓名
perlxstypemap - Perl XS C/Perl 类型映射
商品描述
你越是考虑两种语言之间的接口,你就越会意识到
程序员的大部分工作都必须在数据结构之间进行转换
是所涉及的任何一种语言的母语。 这胜过其他问题,例如
不同的调用约定,因为问题空间要大得多。 有
将数据推入内存的方法比实现函数的方法要多
呼叫。
Perl XS 试图解决这个问题的是类型映射的概念。 在抽象层面上,
Perl XS 类型映射只不过是从特定 Perl 数据转换的方法
结构到某个 C 数据结构,反之亦然。 因为可以有 C 类型
彼此足够相似以保证使用相同的逻辑进行转换,XS
类型映射由唯一标识符表示,此后称为 XS 类型 摘要可点击此连结
文档。 然后您可以告诉 XS 编译器多个 C 类型将被映射
相同的 XS 类型图。
在您的 XS 代码中,当您使用 C 类型定义参数或使用“代码”时:
和“输出:”部分以及 XSUB 的 C 返回类型,它将是
使这变得容易的类型映射机制。
解剖学 of a 类型图
在更实际的术语中,typemap 是代码片段的集合,这些代码片段被
此 xsubpp 编译器将 C 函数参数和值映射到 Perl 值。 类型图
文件可能由标记为“TYPEMAP”、“INPUT”和“OUTPUT”的三个部分组成。 一个
未标记的初始部分被假定为“TYPEMAP”部分。 INPUT 部分告诉
编译器如何将 Perl 值转换为某些 C 类型的变量。 输出
部分告诉编译器如何将某些 C 类型的值转换为值
Perl 可以理解。 TYPEMAP 部分告诉编译器 INPUT 和 OUTPUT 中的哪一个
应该使用代码片段将给定的 C 类型映射到 Perl 值。 部分标签
“TYPEMAP”、“INPUT”或“OUTPUT”必须在一行的第一列中单独开始,
并且必须大写。
每种类型的部分可以出现任意次数,不必出现
根本。 例如,如果所有类型映射都缺少“INPUT”和“OUTPUT”部分
需要做的是将额外的 C 类型与核心 XS 类型(如 T_PTROBJ)相关联。 行那
以散列“#”开头的被认为是注释并且在“TYPEMAP”部分被忽略,但是
在“输入”和“输出”中被认为是重要的。 空行通常被忽略。
传统上,类型映射需要写入一个单独的文件,通常称为
CPAN 发行版中的“typemap”。 使用 ExtUtils::ParseXS(XS 编译器)3.12 版
或 perl 5.16 附带的更好,类型映射也可以直接嵌入到 XS 代码中
使用类似于 HERE-doc 的语法:
类型图:<
...
点击这里
其中“HERE”可以替换为其他标识符,例如普通的 Perl HERE-docs。 全部
下面有关 typemap 文本格式的详细信息仍然有效。
“TYPEMAP”部分每行应包含一对 C 类型和 XS 类型,如下所示。
核心类型映射文件中的一个示例:
类型图
# char* 的所有变体都由 T_PV 类型映射处理
字符 * T_PV
常量字符 * T_PV
无符号字符 * T_PV
...
"INPUT" 和 "OUTPUT" 部分具有相同的格式,即每个未缩进的行
分别启动一个新的输入或输出映射。 新的输入或输出映射必须以
要单独在一行上映射的 XS 类型的名称,后跟实现它的代码
在以下几行缩进。 例子:
INPUT
T_PV
$var = ($type)SvPV_nolen($arg)
T_PTR
$var = INT2PTR($type,SvIV($arg))
稍后我们将了解这些 Perlish 变量的含义。
最后,这里有一个完整的 typemap 文件的例子,用于映射“char *”的 C 字符串
键入 Perl 标量/字符串:
类型图
字符 * T_PV
INPUT
T_PV
$var = ($type)SvPV_nolen($arg)
OUTPUT
T_PV
sv_setpv((SV*)$arg, $var);
这是一个更复杂的例子:假设你想要“struct netconfig”
祝福进入“Net::Config”类。 一种方法是使用下划线 (_)
单独的包名,如下:
typedef 结构 netconfig * Net_Config;
然后提供一个类型映射条目“T_PTROBJ_SPECIAL”,将下划线映射到双冒号
(::),并将“Net_Config”声明为该类型:
类型图
网络配置 T_PTROBJ_SPECIAL
INPUT
T_PTROBJ_SPECIAL
if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")){
IV tmp = SvIV((SV*)SvRV($arg));
$var = INT2PTR($type, tmp);
}
其他
croak(\"$var 不是 ${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")
OUTPUT
T_PTROBJ_SPECIAL
sv_setref_pv($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\",
(无效*)$var);
INPUT 和 OUTPUT 部分在运行中用下划线代替双冒号,给出
想要的效果。 这个例子展示了一些强大的功能和多功能性
打字机设施。
“INT2PTR”宏(在 perl.h 中定义)将整数转换为给定类型的指针,
处理可能的不同大小的整数和指针。 还有
"PTR2IV", "PTR2UV", "PTR2NV" 宏,以另一种方式映射,这在 OUTPUT 中可能有用
部分。
这款 角色 of 此 类型图 文件 in 你的 配电系统
中的默认类型映射 库/ExtUtils Perl 源目录包含许多有用的
Perl 扩展可以使用的类型。 一些扩展定义了额外的类型映射
他们保存在自己的目录中。 这些额外的类型映射可能会引用 INPUT 和
OUTPUT 映射在主类型映射中。 这 xsubpp 编译器将允许扩展自己的
typemap 覆盖默认类型映射中的任何映射。 而不是使用
额外 类型图 文件,类型映射可以用类似heredoc的方式逐字嵌入在XS中
句法。 请参阅有关“TYPEMAP:”XS 关键字的文档。
对于 CPAN 发行版,您可以假设 perl 核心定义的 XS 类型是
已经可用。 此外,核心类型映射具有大量默认 XS 类型
C 类。 例如,如果您只是从 XSUB 返回一个“char *”,则核心类型映射
将具有与 T_PV XS 类型关联的 C 类型。 这意味着你的 C 字符串将是
复制到新标量的 PV(指针值)槽中,该标量将从您的
XSUB 到 Perl。
如果您正在使用 XS 开发 CPAN 发行版,您可以添加自己的名为
类型图 到分配。 该文件可能包含映射类型的类型映射
特定于您的代码或覆盖核心类型映射文件的常见 C 的映射
类型。
共享 类型图 之间 CPAN 分布
从 ExtUtils::ParseXS 版本 3.13_01(带有 perl 5.16 和更好的版本)开始,它是
在多个 CPAN 发行版之间共享类型映射代码相当容易。 一般的想法是
将其作为提供特定 API 的模块共享并让相关模块声明
将其作为内置要求并将类型映射导入 XS。 这样的一个例子
CPAN 上的类型映射共享模块是“ExtUtils::Typemaps::Basic”。 获得它的两个步骤
代码中可用的模块类型映射:
· 将“ExtUtils::Typemaps::Basic”声明为“Makefile.PL”中的构建时依赖项(使用
“BUILD_REQUIRES”),或在你的“Build.PL”中(使用“build_requires”)。
· 在 XS 文件的 XS 部分包含以下行:(不要断行)
包含命令:$^X -MExtUtils::Typemaps::Cmd
-e "打印 embeddable_typemap(q{Basic})"
撰稿 类型图 参赛作品
每个 INPUT 或 OUTPUT 类型映射条目都是将被评估的双引号 Perl 字符串
在存在某些变量的情况下,以获得映射某个 C 类型的最终 C 代码。
这意味着您可以使用诸如
“${ perl 代码,在这里评估为标量引用}”。 一个常见的用例是生成
即使在使用 ALIAS XS 功能时,也会引用真实函数名称的错误消息:
${ $别名? \q[GvNAME(CvGV(cv))] : \qq[\"$pname\"] }
对于很多类型映射示例,请参考 perl 中可以找到的核心类型映射文件
源树位于 库/ExtUtils/类型映射.
可用于插入类型映射的 Perl 变量如下:
· $变量 - 输入或输出变量的名称,例如。 RETVAL 用于返回值。
· $类型 - 参数的原始 C 类型,任何 ":" 替换为 "_"。 例如对于一个类型
"Foo::Bar", $类型 是“Foo__Bar”
· $n类型 - 提供的带有“*”的类型替换为“Ptr”。 例如,对于“Foo*”类型,
$n类型 是“FooPtr”
· $参数 - 堆栈条目,参数输入或输出到,例如 ST(0)
· $argoff - 参数的参数堆栈偏移量。 IE。 第一个参数为 0,
等等
· $pname - XSUB 的全名,包括“PACKAGE”名称,以及任何
“前缀”被剥离。 这是非 ALIAS 名称。
· $包裹 - 由最近的“PACKAGE”关键字指定的包。
· $别名 - 如果当前 XSUB 有任何用“ALIAS”声明的别名,则非零。
是 上市 of 核心 类型图
每个 C 类型由类型映射文件中的一个条目表示,该条目负责
将 perl 变量(SV、AV、HV、CV 等)与该类型相互转换。 下列
部分列出了默认情况下 perl 附带的所有 XS 类型。
T_SV
这只是将 Perl 变量(一个 SV*)的 C 表示传入和传出
XS 层。 如果 C 代码要直接处理 Perl,则可以使用此方法
变量。
T_SVREF
用于传入和返回对 SV 的引用。
请注意,此类型映射在返回时不会减少引用计数
对 SV* 的引用。 另见:T_SVREF_REFCOUNT_FIXED
T_SVREF_FIXED
用于传入和返回对 SV 的引用。 这是 T_SVREF 的固定变体
在返回对 SV* 的引用时适当地减少引用计数。
在 perl 5.15.4 中引入。
T_AVREF
从 perl 级别,这是对 perl 数组的引用。 从 C 级来看,这是一个
指向 AV 的指针。
请注意,此类型映射在返回 AV* 时不会减少引用计数。
另见:T_AVREF_REFCOUNT_FIXED
T_AVREF_REFCOUNT_FIXED
从 perl 级别,这是对 perl 数组的引用。 从 C 级来看,这是一个
指向 AV 的指针。 这是 T_AVREF 的一个固定变体,它减少了引用计数
在返回 AV* 时适当。 在 perl 5.15.4 中引入。
T_HVREF
从 perl 级别,这是对 perl 哈希的引用。 从 C 级来看,这是一个
指向 HV 的指针。
请注意,此类型映射在返回 HV* 时不会减少引用计数。
另见:T_HVREF_REFCOUNT_FIXED
T_HVREF_REFCOUNT_FIXED
从 perl 级别,这是对 perl 哈希的引用。 从 C 级来看,这是一个
指向 HV 的指针。 这是 T_HVREF 的一个固定变体,它减少了引用计数
适当地返回 HV* 时。 在 perl 5.15.4 中引入。
T_CVREF
从 perl 级别,这是对 perl 子程序的引用(例如 $sub = sub { 1 };)。
从 C 级别来看,这是一个指向 CV 的指针。
请注意,此类型映射在返回 HV* 时不会减少引用计数。
另见:T_HVREF_REFCOUNT_FIXED
T_CVREF_REFCOUNT_FIXED
从 perl 级别,这是对 perl 子程序的引用(例如 $sub = sub { 1 };)。
从 C 级别来看,这是一个指向 CV 的指针。
这是 T_HVREF 的一个固定变体,它在以下情况下适当地减少引用计数
返回一个 HV*。 在 perl 5.15.4 中引入。
T_SYSRET
T_SYSRET 类型映射用于处理系统调用的返回值。 它只是
将值从 C 传递给 perl 时有意义(没有传递系统的概念
从 Perl 返回值到 C)。
系统调用在错误时返回 -1(使用原因设置 ERRNO)和(通常)在错误时返回 0
成功。 如果返回值为 -1,则此类型映射返回“undef”。 如果返回值
不是 -1,此类型映射将 0(perl false)转换为“0 but true”(即 perl
true) 或返回值本身,以指示命令成功。
POSIX 模块广泛使用了这种类型。
紫外线
一个无符号整数。
T_IV
一个有符号整数。 当传递给 C 和
传递回 Perl 时转换为 IV。
着色
一个有符号整数。 此类型映射将 Perl 值转换为原生整数类型(
当前平台上的“int”类型)。 当将值返回给 perl 时,它会被处理
与 T_IV 的方式相同。
它的行为与在带有 T_IV 的 XS 中使用“int”类型相同。
T_ENUM
一个枚举值。 用于从 C 传递一个 enum 组件。没有理由传递
C 的枚举值,因为它在 perl 中存储为 IV。
T_布尔
布尔类型。 这可用于向 C 传递真值和假值。
T_U_INT
这是用于无符号整数。 它等效于使用 T_UV 但显式地强制转换
变量键入“无符号整数”。 “无符号整数”的默认类型是 T_UV。
T_短
短整数。 这等效于 T_IV 但显式将返回转换为类型
“短的”。 “short”的默认类型映射是 T_IV。
T_U_SHORT
无符号短整数。 这等效于 T_UV 但显式地将返回值转换为
输入“无符号短”。 “unsigned short”的默认类型映射是 T_UV。
T_U_SHORT 用于标准类型映射中的“U16”类型。
T_LONG
长整数。 这等效于 T_IV 但显式将返回转换为类型
“长”。 “long”的默认类型映射是 T_IV。
T_U_LONG
无符号长整数。 这等效于 T_UV 但显式地将返回转换为
输入“无符号长”。 “unsigned long”的默认类型映射是 T_UV。
T_U_LONG 用于标准类型映射中的“U32”类型。
T_CHAR
单个 8 位字符。
T_U_CHAR
一个无符号字节。
T_FLOAT
一个浮点数。 此类型映射保证将变量转换为
“漂浮”。
T_NV
Perl 浮点数。 类似于 T_IV 和 T_UV,因为返回类型是强制转换的
到请求的数字类型而不是特定类型。
T_DOUBLE
双精度浮点数。 此类型映射保证返回一个变量
强制转换为“双重”。
T_PV
一个字符串(字符 *)。
T_PTR
一个内存地址(指针)。 通常与“void *”类型相关联。
T_PTRREF
与 T_PTR 类似,不同之处在于指针存储在标量中,并且对
该标量返回给调用者。 这可用于隐藏实际指针
来自程序员的值,因为它通常不需要直接从 perl 中获得。
typemap 检查标量引用是否从 perl 传递到 XS。
T_PTROBJ
与 T_PTRREF 类似,只是引用被祝福为一个类。 这允许
要用作对象的指针。 最常用于处理 C 结构体。 这
typemap 检查传入 XS 例程的 perl 对象是否属于正确的类
(或子类的一部分)。
指针被祝福为一个类,该类派生自
指针,但名称中的所有“*”都替换为“Ptr”。
仅对于“DESTROY”XSUB,T_PTROBJ 被优化为T_PTRREF。 这意味着类
检查被跳过。
T_REF_IV_REF
还没
T_REF_IV_PTR
与 T_PTROBJ 类似,指针被祝福为标量对象。 这
不同之处在于,当对象传回 XS 时,它必须是正确的
类型(不支持继承)而 T_PTROBJ 支持继承。
指针被祝福为一个类,该类派生自
指针,但名称中的所有“*”都替换为“Ptr”。
仅对于“DESTROY”XSUB,T_REF_IV_PTR 被优化为 T_PTRREF。 这意味着
跳过类检查。
T_PTRDESC
还没
T_REFREF
与 T_PTRREF 类似,除了被引用标量中存储的指针是
取消引用并复制到输出变量。 这意味着 T_REFREF 将
T_PTRREF 因为 T_OPAQUE 是 T_OPAQUEPTR。 全清?
仅实现了其中的 INPUT 部分(Perl 到 XSUB)并且没有已知用户
在核心或 CPAN 上。
T_REFOBJ
与 T_REFREF 类似,除了它进行严格的类型检查(不支持继承)。
仅对于“DESTROY”XSUB,T_REFOBJ 被优化为T_REFREF。 这意味着类
检查被跳过。
T_OPAQUEPTR
这可用于在 SV 的字符串组件中存储字节。 这里的
数据的表示与 perl 无关,字节本身只是
存储在 SV 中。 假设 C 变量是一个指针(字节被复制
从那个内存位置)。 如果指针指向的是
由 8 个字节表示,然后这 8 个字节存储在 SV(和 长度() 将
报告值为 8)。 此条目类似于 T_OPAQUE。
原则上 解包() 命令可用于将字节转换回数字
(如果已知基础类型是数字)。
此条目可用于存储 C 结构(要复制的字节数为
使用 C 的“sizeof”函数计算)并可用作替代
T_PTRREF 而不必担心内存泄漏(因为 Perl 会清理
SV)。
T_不透明
这可用于在 SV 的字符串部分中存储来自非指针类型的数据。 它
与 T_OPAQUEPTR 类似,只是 typemap 直接检索指针
而不是假设它正在被提供。 例如,如果一个整数被导入到
Perl 使用 T_OPAQUE 而不是 T_IV 表示整数的底层字节
将存储在 SV 中,但实际的整数值将不可用。 即
数据对 perl 是不透明的。
如果数据的底层类型是
字节流是已知的。
T_OPAQUE 支持简单类型的输入和输出。 T_OPAQUEPTR 可以用来传递
如果指针是可接受的,则这些字节返回到 C 中。
隐式数组
xsubpp 支持将打包的 C 数组返回给 perl 的特殊语法。 如果 XS
返回类型为
数组(类型,nelem)
xsubpp 会将“nelem * sizeof(type)”字节的内容从 RETVAL 复制到 SV 和
将其推入堆栈。 这仅在要添加的项目数时才真正有用
返回在编译时是已知的,并且您不介意在您的
SV。 使用 T_ARRAY 将可变数量的参数压入返回堆栈(它们
虽然不会打包为单个字符串)。
这与使用 T_OPAQUEPTR 类似,但可用于处理多个元素。
T_PACKED
调用用户提供的函数进行转换。 对于“输出”(XSUB 到 Perl),一个函数
使用输出 Perl 标量和 C 变量调用名为“XS_pack_$ntype”的
转换自。 $ntype 是要映射到 Perl 的规范化 C 类型。
规范化意味着所有“*”都被字符串“Ptr”替换。 的返回值
该函数被忽略。
相反,对于“INPUT”(Perl 到 XSUB)映射,名为“XS_unpack_$ntype”的函数
以输入 Perl 标量作为参数调用,返回值被强制转换为
映射 C 类型并分配给输出 C 变量。
类型映射结构“foo_t *”的示例转换函数可能是:
静态空隙
XS_pack_foo_tPtr(SV *out, foo_t *in)
{
dTHX; /* 唉,签名不包括 pTHX_ */
HV* 哈希 = newHV();
hv_stores(hash, "int_member", newSViv(in->int_member));
hv_stores(hash, "float_member", newSVnv(in->float_member));
/* ... */
/* 死亡,因为你的堆栈没有被引用 */
sv_setsv(out, sv_2mortal(newRV_noinc((SV*)hash)));
}
从 Perl 到 C 的转换留给读者作为练习,但原型
将会:
静态 foo_t *
XS_unpack_foo_tPtr(SV *in);
而不是必须使用“dTHX”获取线程上下文的实际 C 函数,您
可以定义同名的宏,避免开销。 另外,请记住
可能释放“XS_unpack_foo_tPtr”分配的内存。
T_PACKEDARRAY
T_PACKEDARRAY 类似于 T_PACKED。 实际上,“INPUT”(Perl 到 XSUB)类型映射是
相同,但“OUTPUT”类型映射将附加参数传递给
“XS_pack_$ntype”函数。 第三个参数表示元素的数量
输出,以便函数可以正常处理 C 数组。 变量必须是
由用户声明并且必须具有名称“count_$ntype”,其中 $ntype 是
如上所述,标准化的 C 类型名称。 该函数的签名将用于
上面的例子和“foo_t **”:
静态空隙
XS_pack_foo_tPtrPtr(SV *out, foo_t *in, UV count_foo_tPtrPtr);
就类型映射而言,第三个参数的类型是任意的。 它
只需要与声明的变量一致。
当然,除非您知道“sometype **”C 数组中的元素数量,否则在
您的 XSUB,“foo_t ** XS_unpack_foo_tPtrPtr(...)” 的返回值将很难
解码。 由于细节都是由XS作者(typemap用户)决定的,所以有
几个解决方案,没有一个特别优雅。 最常见的
解决方案是为 N+1 个指针分配内存并将“NULL”分配给第 (N+1) 个
以方便迭代。
或者,首先出于您的目的使用自定义类型映射是
可能更可取。
T_数据单元
还没
T_CALLBACK 回调
还没
T_数组
这用于将 perl 参数列表转换为 C 数组并用于推送
C 数组的内容到 perl 参数堆栈。
通常的调用签名是
@out = array_func(@in);
在数组之前的列表中可以出现任意数量的参数,但输入和
输出数组必须是列表中的最后一个元素。
当用于将 perl 列表传递给 C 时,XS 编写器必须提供一个函数(以
数组类型,但用 'Ptr' 代替 '*') 来分配所需的内存
拿着清单。 应该返回一个指针。 由 XS 编写者来释放
退出函数时的内存。 变量“ix_$var”设置为
新数组中的元素。
当将 C 数组返回给 Perl 时,XS 编写器必须提供一个名为的整数变量
"size_$var" 包含数组中元素的数量。 这用于确定
应该将多少元素推送到返回参数堆栈上。 这不是
输入是必需的,因为 Perl 知道当
例程被调用。 通常这个变量被称为“size_RETVAL”。
此外,每个元素的类型由数组的类型决定。 如果
数组使用类型“intArray *” xsubpp 将自动计算出它包含
“int”类型的变量并使用该类型映射条目来执行每个
元素。 从名称中删除所有指针 '*' 和 'Array' 标签以确定
亚型。
T_STDIO
这用于使用“FILE *”结构将 perl 文件句柄传入和传出 C。
输入输出
这用于使用“PerlIO *”结构将 perl 文件句柄传入和传出 C。
文件句柄可用于读取和写入。 这对应于“+<”模式,
另见 T_IN 和 T_OUT。
有关 Perl IO 抽象层的更多信息,请参阅 perliol。 Perl 一定是
用“-Duseperlio”构建。
没有检查来断言从 Perl 传递给 C 的文件句柄是用
正确的“open()”模式。
提示:perlxstut 教程很好地涵盖了 T_INOUT、T_IN 和 T_OUT XS 类型。
锡
同T_INOUT,但只能使用C返回给Perl的文件句柄
用于阅读(模式“<”)。
输出
与 T_INOUT 相同,但从 C 返回到 Perl 的文件句柄设置为使用
打开模式“+>”。
使用 onworks.net 服务在线使用 perlxstypemap