トップ «前の日記(2007-01-11 (Thu)) 最新 次の日記(2007-01-19 (Fri))» 編集

uDiary

海野秀之(うんのひでゆき)の外部記憶

Twitter (twilog) / RSS / アンテナ / ぶくま

2006|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|08|
2010|01|02|03|05|06|07|10|11|
2011|03|08|
2012|02|04|07|08|10|
2013|01|02|03|05|06|08|11|12|
2014|01|02|05|06|07|08|09|12|
2015|01|02|03|04|

2007-01-17 (Wed)

備忘

CD 買いにいかなあかん → こおた。聞くのがたのしみ。

[Ruby] 初めて C で Ruby の拡張ライブラリを書く

『オブジェクト指向スクリプト言語 Ruby』をみながら、 拡張ライブラリを書いてみた。

Ruby は拡張ライブラリを書きやすい(そのために実行速度が犠牲になっている面すらある) と聞いた(読んだ)ことはあったのだが、実際に書いたことはなかった。 書いてみたら、いや、本当に書きやすい。

/*

  extlibsample.c

  To create ExtLibSample.so:
    ruby -r mkmf -e 'create_makefile("ExtLibSample")' and make

*/

#include "ruby.h"
#include <math.h>

/* First example:

   def euclid_norm_2d(x, y) # x, y: Float.
     sqrt(x*x + y*y)
   end

 */
static VALUE
euclid_norm_2d(self, vx, vy)
     VALUE self, vx, vy;
{
  double x, y;

  Check_Type(vx, T_FLOAT);
  Check_Type(vy, T_FLOAT);

  x = RFLOAT(vx)->value;
  y = RFLOAT(vy)->value;

  return rb_float_new(sqrt(x * x + y * y));
}

/* Second example:

   def euclid_norm(a) # a: Array.
     sum = 0
     a.each {|v| v = v.float; sum += v*v}
     sqrt(sum)
   end

 */
static VALUE
euclid_norm(self, a)
     VALUE self, a;
{
  int i, size;
  double v, sum = 0.0;
  VALUE t;

  Check_Type(a, T_ARRAY);

  size = FIX2INT(rb_funcall(a, rb_intern("size"), 0));

  for(i = 0; i < size; i++){
    t = rb_funcall(a, rb_intern("[]"), 1, INT2FIX(i));
    t = rb_funcall(t, rb_intern("to_f"), 0);
    v = RFLOAT(t)->value;
    sum += v * v;
  }

  return rb_float_new(sqrt(sum));
}

Init_ExtLibSample()
{
  VALUE mExtLibSample = rb_define_module("ExtLibSample");
  rb_define_module_function(mExtLibSample, "euclid_norm_2d", euclid_norm_2d, 2);
  rb_define_module_function(mExtLibSample, "euclid_norm", euclid_norm, 1);
}

呪文をいっぱい唱える必要がなくて、ありがたい。

書いてみたのは、まったく実用的でない、練習のための例ですが、 以下のことがらを含んでいます。

Ruby オブジェクトの型チェックCheck_Type(obj, T_FLOAT)
Ruby Float → C doubleRFLOAT(obj)->value
C double → Ruby Floatrb_float_new((double) x)
Ruby Fixnum → C intFIX2INT(obj)
C int → Ruby FixnumINT2FIX(1)
Ruby オブジェクトのメソッド呼び出しrb_funcall(obj, rb_intern("[]"), 1, INT2FIX(i))
モジュール関数の追加(略)

動かしてみるには、次のようにします:

 % ruby -r mkmf -e 'create_makefile("ExtLibSample")'
 % gmake
 % irb
 irb(main):001:0> require 'ExtLibSample'
 => true
 irb(main):002:0> include ExtLibSample
 => Object
 irb(main):003:0> euclid_norm_2d(2.0, 3.0)
 => 3.60555127546399
 irb(main):004:0> euclid_norm([1.0, 2.0, 3.0])
 => 3.74165738677394

『オブジェクト指向スクリプト言語 Ruby』の8章に書かれている内容を まったく知らないとつらいかな。

ところで、 ワード境界にアラインされた C オブジェクトのポインタ値が偶数になるというのは 言語仕様の一部ではないような気がするのだが(未確認)、 それが奇数になるようなアーキテクチャを思いつかない。 ワード長が9バイトとか?


2006|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|08|
2010|01|02|03|05|06|07|10|11|
2011|03|08|
2012|02|04|07|08|10|
2013|01|02|03|05|06|08|11|12|
2014|01|02|05|06|07|08|09|12|
2015|01|02|03|04|
Categories 3imp | Card | Cutter | Dalvik | Euler | Football | GAE/J | Hand | Haskell | Re:View | Ruby | Scheme | TQD | Tiger | TigerBook読 | UikiTeXi | Verilog | Violin | Web | parconc | tDiary | お勉強 | エントロピー | ツン読 | | 将棋 | 政治について | | 模写してみよう | 確率論 | 設定など | 雑文 | 音声