Perl+XS(二)

经常编写XS的都知道去查相关手册:

perldoc perlguts

gut单词本意指内脏,早期寓意perl内部,因为XS的编写经常需要与perl最底层的那些api打交道,现在且就叫做perlapi吧!

1perl中的数据类型

1perl的主要数据类型

Perl本身有三种主要的数据类型:

标量(scalar)

数组(array)

散列(hash)

这三种类型在perlapi中对应有三种:

SV(Scalar Variables)

AV(Array Variables)

HV(Hash Variables)

这好比c/c++里面的基本类型,比如int, char, string, map,…

任何其它语言和perl进行数据交互,都要转化成perl的主要数据类型;

2perl的其它基本数据类型

对于任何语言,数据类型不外乎整型、浮点、字符串等,在perlapi中,其他的基本数据类型如下所示:

IVinteger variables

UVunsigned integer variables

NVdouble variables

PVstring variables

SVscalar variables

相对于c/c++来说,IV相当于类型intUV相当于类型unsigned intNV相当于类型double;而PV相当于类型char *

基本数据类型的定义就相当于给perl开发者提供了基本的typemaps映射关系,其他复杂的数据结构,最终都可以用整型、浮点和字符串来表示;后面会给出详细描述。

2Scalar Variables

1)创建一个SV

SV *sv = newSV(0);   /* no storage allocated  */

SV *sv = newSV(10);  /* 10 (+1) bytes of uninitialised storage allocated  */

SV允许你分配空间后,继续使用宏命令SvGROW分配空间:

SvGROW(SV*, STRLEN newlen)

2)其他基本数据类型和SV之间的转换

如果没有创建SV,则可以使用下列七种方式直接创建SV

SV*  newSViv(IV);

SV*  newSVuv(UV);

SV*  newSVnv(double);

SV*  newSVpv(const char*, STRLEN);

SV*  newSVpvn(const char*, STRLEN);

SV*  newSVpvf(const char*, ...);

SV*  newSVsv(SV*);

否则已经存在SV,则需要:

void  sv_setiv(SV*, IV);

void  sv_setuv(SV*, UV);

void  sv_setnv(SV*, double);

void  sv_setpv(SV*, const char*);

void  sv_setpvn(SV*, const char*, STRLEN)

void  sv_setpvf(SV*, const char*, ...);

void  sv_vsetpvfn(SV*, const char*, STRLEN, va_list *, SV **, I32, bool *);

void  sv_setsv(SV*, SV*);

值得注意的是newSVpvfsv_setpvf相当于常见的"sprintf"的用法,sv_vsetpvfn则相当于"vsprintf"

当然,还可以给SV赋值PL_sv_undef,表示perl的标量为undef

同理,如果根据SV要返回相对应的基本类型,则需要通过下面这些宏:

SvIV(SV*)

SvUV(SV*)

SvNV(SV*)

SvPV(SV*, STRLEN len)

SvPV_nolen(SV*)

如果想追加一些字串在SV的后面,可以使用:

void  sv_catpv(SV*, const char*);

void  sv_catpvn(SV*, const char*, STRLEN);

void  sv_catpvf(SV*, const char*, ...);

void  sv_vcatpvfn(SV*, const char*, STRLEN, va_list *, SV **, I32, bool);

void  sv_catsv(SV*, SV*);

3SV的检查

I检查SV的值是否为真

SvTRUE(SV*)

II检查变量是否定义

首先使用:

SV*  get_sv("package::varname", FALSE);

获得变量的指针SV *,然后使用宏SVOK判断:

SvOK(SV*)

III判断SV存储的是何种基本类型的数据

想知道perl认为SV里面存储的何种基本类型的数据,可以使用下列宏:

SvIOK(SV*)

SvNOK(SV*)

SvPOK(SV*)

而真正SV里面存储的何种类型数据,需要使用下列宏:

SvIOKp(SV*)

SvNOKp(SV*)

SvPOKp(SV*)

IV获得SV的长度

SvCUR(SV*)

SvCUR_set(SV*, I32 val)

V获得SV的末尾字串的指针

SvEND(SV*)

3Array Variables

1)创建一个AV

SV一样:

AV*  newAV();

另外,还有一种方法:

AV*  av_make(I32 num, SV **ptr);

2)删除数组

I清空数组元素

void  av_clear(AV*);

II删除数组

void  av_undef(AV*);

3)数组元素的获取和插入

SV**  av_fetch(AV*, I32 key, I32 lval);

SV**  av_store(AV*, I32 key, SV* val);

4)数组的基本特性

和大多数数组的特性的定义一样,AV定义了四种方法:

void  av_push(AV*, SV*);

SV*   av_pop(AV*);

SV*   av_shift(AV*);

void  av_unshift(AV*, I32 num);

值得注意的是av_unshift本身不插入一个数组元素,只是在AV中新增加一个空位,以供av_store来添加一个元素。

5AV的其它特性

I计算本身数组的元素的个数

I32   av_len(AV*);

II增加数组本身的元素个数分配

void  av_extend(AV*, I32 key);

值得注意的是key+1的大小必须大于AV本身的元素个数,否则此函数不会做任何事情。

III获取perl数组变量的指针

SV一样:

AV*  get_av("package::varname", FALSE);

4Hash Variables

1)创建一个HV

HV*  newHV();

2)删除散列

AV一样:

void   hv_clear(HV*);

void   hv_undef(HV*);

3)散列key/value对的获取和插入

SV**  hv_store(HV*, const char* key, U32 klen, SV* val, U32 hash);

SV**  hv_fetch(HV*, const char* key, U32 klen, I32 lval);

4)散列的特性

I检查散列key是否存在,并删除之(hv_delete)

bool  hv_exists(HV*, const char* key, U32 klen);

SV*   hv_delete(HV*, const char* key, U32 klen, I32 flags);

II HE类型

Perl使用了一种特殊的结构体来保存key/value对,key是一个字符串指针(char *),而value是一个SV的指针(SV *),下面所示几种都是HE类型的用法:

I32    hv_iterinit(HV*);

        /* Prepares starting point to traverse hash table */

HE*    hv_iternext(HV*);

        /* Get the next entry, and return a pointer to a

           structure that has both the key and value */

char*  hv_iterkey(HE* entry, I32* retlen);

        /* Get the key from an HE structure and also return

           the length of the key string */

SV*    hv_iterval(HV*, HE* entry);

        /* Return an SV pointer to the value of the HE

           structure */

SV*    hv_iternextsv(HV*, char** key, I32* retlen);

        /* This convenience routine combines hv_iternext,

           hv_iterkey, and hv_iterval.  The key and retlen

           arguments are return values for the key and its

           length.  The value is returned in the SV* argument */

如果要从HE类型中获得keyvalue,需要使用下面这些宏:

HePV(HE* he, STRLEN len)

HeVAL(HE* he)

HeHASH(HE* he)

HeSVKEY(HE* he)

HeSVKEY_force(HE* he)

HeSVKEY_set(HE* he, SV* sv)

这有两个更低级的宏是定义了的,一般仅仅用作处理key,而不能当作SV *来用:

HeKEY(HE* he)

HeKLEN(HE* he)

III获取perl散列变量的指针

HV*  get_hv("package::varname", FALSE);

5)散列的其它特性

自从perl 5.004以来,perl也支持下面的几种特性:

HE*     hv_fetch_ent  (HV* tb, SV* key, I32 lval, U32 hash);

HE*     hv_store_ent  (HV* tb, SV* key, SV* val, U32 hash);

 

bool    hv_exists_ent (HV* tb, SV* key, U32 hash);

SV*     hv_delete_ent (HV* tb, SV* key, I32 flags, U32 hash);

 

SV*     hv_iterkeysv  (HE* entry);

5References Variables

引用是一种特殊的标量类型,其值可以指向perl的任何主要数据类型。

1)创建一个RV

SV* newRV_inc((SV*) thing);

SV* newRV_noinc((SV*) thing);

2)解除引用

SvRV(SV*)

3RV的检查

I检查SV是否是一个RV

SvROK(SV*)

IIRV的所指代的类型

SvTYPE(SvRV(SV*))

SvTYPE将返回下列九种类型:

SVt_IV    Scalar

SVt_NV    Scalar

SVt_PV    Scalar

SVt_RV    Scalar

SVt_PVAV  Array

SVt_PVHV  Hash

SVt_PVCV  Code

SVt_PVGV  Glob (possible a file handle)

SVt_PVMG  Blessed or Magical Scalar

4)面向对象

在下面这些函数或宏的定义中,xs所需要定义的类型映射经常需要用到引用中的OO概念。

SV* sv_bless(SV* sv, HV* stash);

参数sv必须是一个引用,参数stash将指定这个引用属于哪个类。

SV* newSVrv(SV* rv, const char* classname);

针对rv创建一个新的SV,如果classname存在话,则rv blessed在指定的classname上。

SV* sv_setref_iv(SV* rv, const char* classname, IV iv);

SV* sv_setref_uv(SV* rv, const char* classname, UV uv);

SV* sv_setref_nv(SV* rv, const char* classname, NV iv);

复制integer, unsigned integerdouble三种类型到引用类型rv上,如果classname存在话,则rv blessed在指定的classname上。同理:

SV* sv_setref_pv(SV* rv, const char* classname, PV iv);

SV* sv_setref_pvn(SV* rv, const char* classname, PV iv, STRLEN length);

测试一个SV是否blessed在指定的class,但不能检查继承关联,可以使用:

int  sv_isa(SV* sv, const char* name);

测试一个SV是否是一个引用且blessed object,可以使用:

int  sv_isobject(SV* sv);

测试一个SV是否起源于指定的classSV是一个引用或一个类名的字串,可以使用:

bool sv_derived_from(SV* sv, const char* name);

5)引用计数

int SvREFCNT(SV* sv);

SV* SvREFCNT_inc(SV* sv);

void SvREFCNT_dec(SV* sv);

引用计数主要是perl内存的一种记录方式,如果使用了newRV_inc,那么则增加了一次引用计数,如果在XS的子程序不对new出来引用进行消亡,则perl不会自动释放这块new出来的内存,直到perl程序结束,所以使用引用计数的时候,一定要注意内存泄露(memory leak)

针对引用计数的这种情况,可以使用下列函数来将引用的值赋值给一个最终消亡的变量:

SV*  sv_newmortal()

SV*  sv_2mortal(SV*)

SV*  sv_mortalcopy(SV*)

值得注意的是:sv_newmortal函数是申请一个变量SV,还需要使用sv_set*来进行赋值给SV后使用。

6Glob Variables

perl的世界里,经常看到定义了一个classname(package name)赋值给一个SV,一个stash就表示这个样子的hash,其中每个key是一个符号名字,每个valuehash table中就是一个GV

GV常见包含了以下几种类型:

Scalar Value

Array Value

Hash Value

I/O Handle

Format

Subroutine

1)对于特定的package获取一个stash指针

HV*  gv_stashpv(const char* name, I32 create)

HV*  gv_stashsv(SV*, I32 create)

2)对于一个引用,获取一个stash指针

HV*  SvSTASH(SvRV(SV*));

接着,可以做一些额外的操作,比如获得stashpackage name

char*  HvNAME(HV* stash);

甚至你可以重新re-bless

SV*  sv_bless(SV*, HV* stash)

3GV的检查

为了使各种各样的数据类型转换成统一的SV,使用sv_set*v即可,但是原来的数据类型将被计入,可以使用下列四种宏来查看:

SvIOK_on

SvNOK_on

SvPOK_on

SvROK_on

7Magic Variables

MV实际上是一个struct,可能最新的perl里,struct中的成员会有所变化,但它还是一种特殊特征的SV

1)魔术变量的分配

void sv_magic(SV* sv, SV* obj, int how, const char* name, I32 namlen);

2)魔术变量的特性

I增加magicHV

void hv_magic(HV *hv, GV *gv, int how);

IISV中移除magic

void sv_unmagic(SV *sv, int type);

3Magic Virtual Tables

"MGVTBL"提供了下列五种函数:

int  (*svt_get)(SV* sv, MAGIC* mg);

int  (*svt_set)(SV* sv, MAGIC* mg);

U32  (*svt_len)(SV* sv, MAGIC* mg);

int  (*svt_clear)(SV* sv, MAGIC* mg);

int  (*svt_free)(SV* sv, MAGIC* mg);

4)查看magic

MAGIC* mg_find(SV*, int type); /* Finds the magic pointer of that type */

int mg_copy(SV* sv, SV* nsv, const char* key, STRLEN klen);

Monthly Archives

Pages

Powered by Movable Type 7.7.2

About this Entry

This page contains a single entry by Cnangel published on September 5, 2009 11:19 AM.

Perl+XS(一) was the previous entry in this blog.

Perl+XS(三) is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.