Devel::Peek::Dumpで見るSVのボディの型
今までXSでSvTYPE(sv)をするとそのsvの型が返ってくると考えていたのだが,最近それは誤りであると気づいた。SvTYPE(sv)が返すのはそのsvのボディの型であり,それがsvの内容を表現していることもあれば,無関係のこともある。
具体的には,そのsvが配列(AV),ハッシュ(HV),サブルーチン(CV),型グロブ(GV)などであれば,SvTYPE(sv)が返すのは実際にそのsvの型と一致するが,それ以外のスカラー値の場合はsvのフラグを見なければ型を特定できない。
それを示すのが次のスクリプトである:
#!perl use strict; use Devel::Peek; my $x; # $xはundef Dump $x; # -> SvTYPEはNULL $x = \10; # 一旦リファレンスを代入 $x = undef; # $xはundef Dump $x; # -> SvTYPEはRV (内容とSvTYPEが不一致) $x = *foo; # SvTYPEはPVGV $x = undef; # $xはundef Dump $x; # -> SvTYPEはPVMG (内容とSvTYPEが不一致) __END__
結果はバージョンによって変わるが,5.10.0では以下のようになる
SV = NULL(0x0) at 0xa081b34 REFCNT = 1 FLAGS = (PADMY) SV = RV(0xa081b40) at 0xa081b34 REFCNT = 1 FLAGS = (PADMY) SV = PVMG(0xa07b46c) at 0xa081b34 REFCNT = 1 FLAGS = (PADMY) IV = 168471720 NV = 0 PV = 0xa091774 "*main::foo"\0 CUR = 10 LEN = 12
二番目のSV = RV(...)は何かのリファレンスのように見えるかもしれないが,undefである。もし有効なリファレンスであれば,FLAGSにROKがあるはずだ。三番目のSV = PVMG(...)は特殊な文字列のように見えるかもしれないが,これもundefである。これも同様に,もし文字列であればFLAGSにPOKがあるはずだ。
したがって,XSレベルでスカラーを期待するsvに対してswitch(SvTYPE(sv)){ ... }としたくなったときは注意が必要である。