2011年12月11日日曜日

ruby/dlでの構造体の扱いについて

ruby/dlでlibaoを使うでCのライブラリをCでラッパを書かずにrubyから利用できることは分かった。 ただ、構造体の扱いが少々面倒臭いことが分かったので、纏めておく。

構造体のメンバに構造体が存在する場合

構造体の定義はDL::Importer#structを用いて行うことができるが、 構造体のメンバに構造体が存在する場合、それを自動的に展開はしてくれない。

例えば、以下のような2つの構造体があったとする。

typedef struct info{
  int no;
  char *name;
} info;

typedef struct namelist{
  info first;
  info second;
  info third;
} namelist;

これをDL::Importer#structに渡す際には、以下のように書きたくなるが、 これではnamelist構造体のメンバであるinfoがうまく展開されない。

Info = struct(['int no', 'char *name'])
NameList = struct(['info first', 'info second', 'info third'])

以下のように手動で展開する必要がある。

NameList = struct(['int first_no', 'char *first_name',
  'int second_no', 'char *second_name', 
  'int third_no', 'char *thrd_name'])

関数の引数に構造体のポインタを渡す場合

関数の引数に構造体のポインタを渡す場合は、ruby/dl側でvoid *に自動的に変換するようなので、 そのまま渡して構わない模様。

# int check(namelist *list);
extern('int check(namelist *list)')

関数の引数に構造体そのものを渡す場合

aliasできる型が無いのでDL::Imprter#typealiasも利用できないし、どうしたらいいものか…と悩み続けて数週間。 入れ子の構造体同様に定義してしまえばよいということにようやく気がついた。

# int check(namelist list);
extern('int check(int first_no, char *, int , char *,  int, char *)')

あとはrubyから呼ぶ際にメンバの順番通りに引数を渡せば良い。

ここまでくるのにだいぶ長期間悩んでしまったが、まぁなんとかなったのでよしとしたいところ…orz。

0 件のコメント:

コメントを投稿