=head1 NAME
如何从perl中将数组传入xs=head1 Preworkh2xs -A -n Array
=head2 从perl给c传递数组 typedef int intArray;
int sum(int count, intArray * array); //c原型 intArray * T_ARRAY // typemap
int sum_as_list(array, ...)
intArray * array
CODE:
RETVAL = sum(ix_array, array);
OUTPUT:
RETVAL
CLEANUP:
Safefree(array)从perl中传递数组给c需要经过perl预定义的T_ARRAY的处理, T_ARRAY定义在perl的标准typemap中。T_ARRAY会生成一个ix_${var}的变量来表示传入参数的个数,比如在上面的例子中,生成ix_array。$var为传入参数和传到c中的参数名 在c中当然需要有一个保存传入参数的数组,T_ARRAY假设存在一个叫做$ntype(这里为intAarryPtr)的函数,这个函数返回一个指向内存的指针,T_ARRAY使用这个指针来保存参数列表,自然的,这个指针需要在c函数返回后被释放,不然便会造成内存泄漏。这就是上面例子中CLEANUP的作用。当然我们也可以自己定义,在$ntype中添加释放内存的操作。比如!!!! 改正,perl不会给我们自动提供实现提供内存的函数,这些还得我们自己定义.
//这是默认实现
intArray * intArrayPtr(int num){
intArray * array;
New(0,array, num, intArray);
return array
} //无须cleanup的实现版本
void * intArrayPtr(int num){
SV * mortal;
mortal = sv_2mortal(NEWSV(0,num * sizeof(intArray)));
return SvPVX(mortal);
}
c里面是如何决定array的类型的?答案是从$ntype中猜测,perl把ntype中的array和ptr字段去除,剩下的字段就是数组的类型。在这里,把intArrayPtr去掉便成了int 标准的T_ARRAY typemap可以在/usr/lib/perl5/5.10/ExtUtils/typemap中找到
=head2 给c传递数组引用 int
sum_as_ref(avref)
AV * avref
PREINIT:
int len;
int i;
SV ** elem;
intArray * array;
CODE:
len = av_len(avref) + 1;
array = intArrayPtr(len);
for(i = 0; i<len; i++){
elem = av_fetch(avref, i, 0);
if(elem == NULL){
array[i] = 0;
}
else{
array[i] = SvIV(*elem);
}
}
RETVAL = sum(len, array);
OUTPUT:
RETVAL在这里av_fetch返回的是一个指向sv的引用的引用,其第三个参数是bool lvalue,当这个参数被设置时,如果数组不够大,perl会自动根据第二个参数index扩充数组。
=head2 使用pack给c传递参数 int
sum_as_packed(packed)
SV * packed
PREINIT:
int len;
intArray * array;
CODE:
array = (intArray *) SvPV_nolen(packed);
len = SvCUR(packed)/sizeof(intArray);
RETVAL = sum(len, array);
OUTPUT:
RETVAL
int
sum_as_packed2(len, packed)
int len
char * packed
CODE:
RETVAL = sum(len,(intArray *)packed);
OUTPUT:
RETVALSvPV无非是从SV返回一个PV,而SvCUR返回的是Sv的大小。=cut
Posted via email from 单行道


没有评论:
发表评论