经常编写XS的都知道去查相关手册:
perldoc perlguts
gut单词本意指内脏,早期寓意perl内部,因为XS的编写经常需要与perl最底层的那些api打交道,现在且就叫做perlapi吧!
1,perl中的数据类型
(1)perl的主要数据类型
Perl本身有三种主要的数据类型:
①标量(scalar)
②数组(array)
③散列(hash)
这三种类型在perlapi中对应有三种:
①SV(Scalar Variables)
②AV(Array Variables)
③HV(Hash Variables)
这好比c/c++里面的基本类型,比如int, char, string, map,
任何其它语言和perl进行数据交互,都要转化成perl的主要数据类型;
(2)perl的其它基本数据类型
对于任何语言,数据类型不外乎整型、浮点、字符串等,在perlapi中,其他的基本数据类型如下所示:
IV:integer variables
UV:unsigned integer variables
NV:double variables
PV:string variables
SV:scalar variables
相对于c/c++来说,IV相当于类型int;UV相当于类型unsigned int;NV相当于类型double;而PV相当于类型char *。
基本数据类型的定义就相当于给perl开发者提供了基本的typemaps映射关系,其他复杂的数据结构,最终都可以用整型、浮点和字符串来表示;后面会给出详细描述。
2,Scalar 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*);
值得注意的是newSVpvf和sv_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*);
(3)SV的检查
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*)
3,Array 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来添加一个元素。
(5)AV的其它特性
I计算本身数组的元素的个数
I32
av_len(AV*);
II增加数组本身的元素个数分配
void
av_extend(AV*, I32 key);
值得注意的是key+1的大小必须大于AV本身的元素个数,否则此函数不会做任何事情。
III获取perl数组变量的指针
同SV一样:
AV*
get_av("package::varname", FALSE);
4,Hash 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类型中获得key和value,需要使用下面这些宏:
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);
5,References Variables
引用是一种特殊的标量类型,其值可以指向perl的任何主要数据类型。
(1)创建一个RV
SV* newRV_inc((SV*) thing);
SV* newRV_noinc((SV*) thing);
(2)解除引用
SvRV(SV*)
(3)RV的检查
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 integer或double三种类型到引用类型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是否起源于指定的class,SV是一个引用或一个类名的字串,可以使用:
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后使用。
6,Glob Variables
在perl的世界里,经常看到定义了一个classname(package name)赋值给一个SV,一个stash就表示这个样子的hash,其中每个key是一个符号名字,每个value在hash 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*));
接着,可以做一些额外的操作,比如获得stash中package name:
char*
HvNAME(HV* stash);
甚至你可以重新re-bless:
SV*
sv_bless(SV*, HV* stash)
(3)GV的检查
为了使各种各样的数据类型转换成统一的SV,使用sv_set*v即可,但是原来的数据类型将被计入,可以使用下列四种宏来查看:
SvIOK_on
SvNOK_on
SvPOK_on
SvROK_on
7,Magic Variables
MV实际上是一个struct,可能最新的perl里,struct中的成员会有所变化,但它还是一种特殊特征的SV。
(1)魔术变量的分配
void sv_magic(SV* sv, SV* obj, int how, const
char* name, I32 namlen);
(2)魔术变量的特性
I增加magic到HV
void hv_magic(HV *hv, GV *gv, int how);
II从SV中移除magic
void sv_unmagic(SV *sv, int type);
(3)Magic 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);