Inline::C 足够聪明,可以SV
根据 C 函数的类型签名从 's 中提取值。但是,如果您想将复杂的 Perl 结构传递给 C 函数,则需要使用Perl API来提取值。因此,对于此问题,您需要了解以下内容:
数组是 C 的一个实例,struct
称为AV
. 引用由被struct
调用的 an实现RV
。所有这些都是struct
名为SV
.
所以为了使这个函数工作,我们需要做一些事情。
- 将参数类型更改为
SV *
(指向 的指针SV
)。
- 使用 API 检查此特定
SV
值是否是引用而不是其他类型的标量
- 检查 RV 以确保它指向一个数组而不是其他东西。
- 取消引用
RV
以获得SV
它指向的那个。
- 因为我们知道这
SV
是一个数组,所以将其转换为AV
并开始使用它。
- 查找该数组的第三个元素,即另一个
SV
.
- 检查
SV
我们从数组中得到的 是一个适合 C 的数值printf
- 从中提取实际数值
SV
。
- 打印消息
因此,将所有这些放在一起,我们会得到这样的结果:
use Inline C;
my @abc = (1.9, 2.3, 3.8);
foo( \@abc );
__END__
__C__
void foo( SV *abc )
{
AV *array; /* this will hold our actual array */
SV **value; /* this will hold the value we extract, note that it is a double pointer */
double num; /* the actual underlying number in the SV */
if ( !SvROK( abc ) ) croak( "param is not a reference" );
if ( SvTYPE( SvRV( abc ) ) != SVt_PVAV ) croak( "param is not an array reference" );
/* if we got this far, then we have an array ref */
/* now dereference it to get the AV */
array = (AV *)SvRV( abc );
/* look up the 3rd element, which is yet another SV */
value = av_fetch( array, 2, 0 );
if ( value == NULL ) croak( "Failed array lookup" );
if ( !SvNOK( *value ) ) croak( "Array element is not a number" );
/* extract the actual number from the SV */
num = SvNV( *value );
printf( "C = %f\n", num );
}
Kinda 让您欣赏 Perl 在幕后所做的工作。:)
现在,您不必像该示例那样非常明确。您可以通过内联处理来摆脱一些临时变量,例如
printf( "C = %f\n", SvNV( *value ) );
将消除申报的需要num
。但我想弄清楚在 C 中遍历 Perl 结构需要多少解引用和类型检查。
正如@mob 在下面指出的那样,您实际上不必做所有这些工作(尽管熟悉它的工作原理是个好主意。)
Inline::C 足够聪明,如果您将函数声明为
void foo( AV *abc ) {
...
}
它会自动AV
为您打开包装,您可以直接进入av_fetch
步骤。
如果所有这些对您来说都令人困惑,我强烈建议您看一下:
- Perlguts插图PDF,然后
perlguts
手册页,然后
- The Inline::C Cookbook,同时咨询
perlapi
手册页。