CライブラリとRuby間でバイナリデータのやりとり

色々あって、CでRubyのライブラリを作成中。
http://www.loveruby.net/w/RubyExtensionProgrammingGuide.htmlを参考にしています。
まあ基本は上記サイトとか,Rubyに付属のREADME.EXT.jaを見れば大体分かる。


でタイトルの件だけど、今まで不思議だったのは、
例えばTCPとか、バイナリデータが書いてあるファイルを読み込むとStringで取得できる。
このデータをライブラリ側に渡して、ライブラリ側で正しく読むには、
memcpy()を使えばいい。


とりあえず簡単なサンプル。
「file」というファイルにstruct test_tのデータをあらかじめ作っておく。

#include <stdio.h>
#include <string.h>
#include <ruby.h>

struct test_t{
        int a;
        int b;
};

VALUE test_hoge(VALUE self, VALUE str){
        struct test_t data;

        StringValue(str);
        memcpy(&data, RSTRING(str)->ptr, RSTRING(str)->len);
        printf("a:%d b:%d\n", data.a, data.b);

        return Qnil;
}

void Init_test(void){
        VALUE test;

        test = rb_define_class("Test", rb_cObject);
        rb_define_method(test, "hoge", test_hoge, 1);
}


ライブラリを使う側。

#!/usr/bin/env ruby

require 'test.so'

str = File.read("file")

test = Test.new
test.hoge(str)


これで問題無しに読み込める。


結局、Cで型が分からない場合は文字列で保存するしかない。
でFileだろうが、TCPだろうがCレベルでは文字列(char)として持っていて、
それをRuby側でみるとString型なのでpとかで出力すると、
それぞれに対応したASCIIとして出力されるみたい。