拡張ライブラリチュートリアルをやってみる#2

続き.

数値のやりとり

整数の加算をやってみる.

処理実体
  • add.c
int add(a, b)
     int a, b;
{
  return(a + b);
}

int を 2 つ受け取って加算した結果を int で返す.コードに問題ないかをちょっとテストのために実行してみる

  • main.c
#include <stdio.h>

int add(int a, int b);

int main()
{
  int a, b;

  a = 1;
  b = 2;
  printf("%d + %d = %d\n", a, b, add(a, b));
}
% cc -o add add.c main.c
% ./add
1 + 2 = 3

まあ普通に実行される.

C と Ruby の接続

Ruby では数値ですらオブジェクトなので, C の int 型に変換する必要がある.それをやってくれるのが,以下のマクロ・関数らしい.

FIX2INT
Ruby オブジェクトを int 型へ変換する
NUM2INT
Numeric かどうかをチェックしてから int 型へと変換する.Numeric でない場合は例外を吐く.
INT2FIX
signed int(31bit) を Ruby の Fixnum へと変換する.
INT2NUM
int を Ruby の Interger へ変換する.桁あふれの場合は Bignum へと自動拡張して変換する.
NUM2DBL
Numeric かどうかをチェックしてから double 型へと変換する.Numeric でない場合は例外を吐く.
rb_float_new(float)
float/double 型の実数を Float 型へと変換する.

そしてこれを使ってラッパーを作る.

  • test2.c
#include "ruby.h"

int add(int a, int b);

VALUE wrap_add(self, aa, bb)
     VALUE self, aa, bb;
{
  int a, b, result;

  a = FIX2INT(aa);        // FIX2INT によって,VALUE 型構造体を int 型へ変換する
  b = FIX2INT(bb);        // 同上
  result = add(a, b);
  return INT2FIX(result); // INT2FIX によって,int 型を VALUE 型構造体へ変換する
}

void Init_test()
{
  VALUE module;

  module = rb_define_module("Test"); // Test モジュールを生成する
  rb_define_module_function(module, "add", wrap_add, 2); // module(Test モジュール) に add メソッドを,引数の数を2として登録する
}
処理の流れ

基本的に前回と一緒.ことなるのは上記のマクロ使って C の型と Ruby オブジェクトを相互変換していること.

コンパイルして実行する

extconf.rb は前回と同じのを使う.

  • extconf.rb
require 'mkmf'
create_makefile('test')
% ruby extconf.rb
% make
% ruby -r'test' -e'puts Test.add(1,2)'
3

Ruby オブジェクトと C の型の相互変換用のマクロなり関数なりがあるので,それを使えば接続にはそれほど苦労しない印象.