ケーズメモ このページをアンテナに追加 RSSフィード

2008-12-21

XS入門その4 typemap - CとPerlの型変換

[注意書き]

書いてる最中にデータが飛んだので書き直しているのですが、多分後から思い出して追記すると思います。

[/注意書き]

ここまでXSのコードの中で、変数の型はCの型で書いてきました。が、考えてみればおかしな話で、Perlから受け渡されるデータの型はスカラ配列ハッシュなのになぜ、Cの型で記述して良いのかという問題があります。スカラは数値でも文字列でもいいわけですし、数値でもintであろうとdoubleであろうとPerlでコードを書いているときにその違いを気にすることはありません。

今回も結論から先に書きますが、typemapというファイルがCの型とXSで扱うPerlの型の対応関係が記述されていて、それを元に解釈されているという仕組みになっています。今回は

  1. XSで扱うPerlの代表的な型を知る
  2. XSで扱うPerlの型の変換について学ぶ
  3. Perlからの受け渡し、Perlへ値を戻す場合にどのような処理が行われているかある程度理解する
  4. typemapの記述を理解する
  5. ディフォルトのtypemapに無い型を定義して実際に使ってみる

ということをしていこうと思います。


XSで扱う型

perldocを参照して

$ perldoc perlguts

としてターミナルで読んでもよいのですが、ブラウザの方が読みやすいので以下のサイトを参照しました。

perlguts - perldoc.perl.org

http://perldoc.perl.org/perlguts.html

最初のVariablesのDatatypesにPerlの基本型について書かれています。

などがあるようです。


XSの型変換などの関数

詳しくは

perlapi - perldoc.perl.org

http://perldoc.perl.org/perlapi.html

で調べられますが、ここではtypemapが軽く読めるようになればいいので、基本的な関数の形をSVの場合を例に挙げます。

関数内容
SV* newSV(STRLEN len)SV型の変数を生成
svtype SvTYPE(SV* sv)SVの詳しい型を調べる。戻り値のsvtypeはSVt_IVなどSVt_[型名]
U32 SvIOK(SV* sv)引数変数SVが特定の型(例の場合はIV)かどうか調べる関数。指定した型ではない場合は0が返る
IV SvIV(SV* sv)SV型の変数をIVに変換。同様にNVに変換するときにはSvNVとなる
void sv_setsv(SV* dsv, SV* ssv)dsvにssvをセットする

HVやAV、RVにはSVの他にも関数がありますが、とりあえずはこのくらいで。SV以外の型の場合は関数Sv(もしくはSV)の部分を適宜使用する型で読み替えてください。


Perlからの値の受け取りと値戻し

PerlからXSの関数が呼ばれたさいの引数はSTという特殊なスタックに格納されています。第一引数であればST(0)で第二引数であればST(1)になります。Perlへの戻り値は既にこれまでのコード内で書いていますが、.xsファイルでRETVALという変数を使います。

詳しい話はmakeしてHoge.xsから生成されたCのコードのHoge.cの中を見ていくときにまたします。


typemapの記述

ディフォルトで指定されるtypemapは自分の環境(Ubuntu 8.04)の場合は/usr/share/perl/5.8.8/ExtUtils/typemapにありました。typemapは以下のような形式で記述されています。

$ less /usr/share/perl/5.8.8/ExtUtils/typemap
# basic C types
int			T_IV
unsigned		T_UV
unsigned int		T_UV
long			T_IV

(中略)

#############################################################################
INPUT

(中略)

T_IV
        $var = ($type)SvIV($arg)

(中略)

#############################################################################
OUTPUT

(中略)

T_IV
        sv_setiv($arg, (IV)$var);

(後略)

上記ファイルを見るとtypemapは以下の3つのパートから構成されています。

  1. 型のマッピング部分
  2. INPUT部分
  3. OUTPUT部分

最初の方にCの基本的な型のCで記述されたPerlの型でのマップの定義があります。例えば、Cのint型はT_IV型ということになります。

次にINPUT以下の部分。ここにはこの型に値を渡された場合の処理が書かれています。例示した部分では受け取ったSV値をIV値に変換しています。

最後にOUTPUT以下の部分。ここにはこの型が値を渡す場合の処理が書かれています。例示した部分ではIVの値を渡しています。

INPUTとOUTPUTで値のセットの方法が異なることについては今回はスルーということで。


自分でtypemapを書いてみる

ディフォルトのtypemapの他に、h2xsで生成されたディレクトリ内にtypemapファイルを作成して自分で型定義をすることで、ディフォルトでは定義されていない型をXSで使うことができるようになります。

単純な例ですが、ディフォルトのtypemapにはconst charが定義されていないのでtypemapで定義してみます。h2xsで生成されたディレクトリ内でtypemapを以下の内容で作成します。

TYPEMAP
const char *  T_PV

INPUT/OUTPUT部分はディフォルトのtypemapに定義されたT_PVの処理でよいので、この場合は記述する必要はないようです。

そして.xsファイルは以下のようにします。

// ヘッダ部分略
void
hello(name, repeat)
    const char * name
    int repeat
    CODE:
        for (int i=0; i<repeat; i++) {
            printf("Hello %s!\n", name);
        }

と、この場合はchar*でもconst char*でも変わらない気がしますが……。この状態でMakefileを作成します。

$ perl Makefile.PL && make

これでconst char*が使える状態になっています。同様に自分がtypedefした型もtypemapにマッピングする型と、INPUT, OUTPUTを記述すれば利用することができます。

こちらはまた次に自作ライブラリインポート方法と併せて書きたいと思います。


今回ざっとXSの型について紹介したので、次回はハッシュリファレンス引数にしてハッシュ処理をXSでする方法について書きたいと思います。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証