<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tomoyuki Sahara</title>
    <description>The latest articles on DEV Community by Tomoyuki Sahara (@tsahara).</description>
    <link>https://dev.to/tsahara</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F44640%2Ff768b790-818e-4372-8a09-65f25853c708.jpeg</url>
      <title>DEV Community: Tomoyuki Sahara</title>
      <link>https://dev.to/tsahara</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tsahara"/>
    <language>en</language>
    <item>
      <title>mruby の String から C 言語の文字列を取り出す正しい方法</title>
      <dc:creator>Tomoyuki Sahara</dc:creator>
      <pubDate>Wed, 01 Apr 2020 10:20:38 +0000</pubDate>
      <link>https://dev.to/tsahara/mruby-string-c-3nec</link>
      <guid>https://dev.to/tsahara/mruby-string-c-3nec</guid>
      <description>&lt;p&gt;&lt;strong&gt;注: この記事は 2015 年に執筆したものです。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;mruby には、Ruby 文字列 (String クラスのインスタンス) から C 言語の文字列(&lt;code&gt;char *&lt;/code&gt;) を取り出す手段が三つあります。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;RSTRING_PTR&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mrb_string_value_cstr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mrb_str_to_cstr&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;残念ながらどれも癖があって使い方を間違えるとあっさりバグの原因となります。それぞれの特徴をかんたんに記すと、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;RSTRING_PTR&lt;/code&gt; は効率は良いが危険。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mrb_string_value_cstr&lt;/code&gt; はそこそこ便利だが注意が必要。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mrb_str_to_cstr&lt;/code&gt; は効率は劣るが使いやすい。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;といったところです。以下、順に解説します。&lt;/p&gt;

&lt;h2&gt;
  
  
  RSTRING_PTR
&lt;/h2&gt;

&lt;p&gt;RSTRING_PTR は、文字列オブジェクトが内部で保持している、文字列を表すバイト列を直接取り出すマクロです。このマクロを関数と見たてたときの呼び出し規約を書くと以下のようになります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;RSTRING_PTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb_value&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;mruby では String オブジェクトは &lt;code&gt;struct RString&lt;/code&gt; という構造体として実装されています。RSTRING_PTR マクロは、struct RString が直接または間接的に保持しているバイト列(&lt;code&gt;char *&lt;/code&gt;)へのポインタを取り出すものです。そのため、利用者には struct RString の実装に熟知していることが求められます。ありがちな誤りとして、以下の二つがあります:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;RSTRING_PTR が適切に NUL 終端されていないケースを無視している。&lt;/li&gt;
&lt;li&gt;struct RString が示すバイト列がメモリ空間上で移動したのに、古いポインタ値を使い続ける。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;RSTRING_PTR が示すバイト列は、多くの場合には適切に NUL 終端されています。しかし、Ruby の文字列の実装ではバイト列を他の文字列オブジェクトと共有する場合があります。たとえば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"a"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="n"&gt;s2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;という Ruby のコードは s1 と s2 という二つの Ruby 文字列を生成しますが、これらのオブジェクトに RSTRING_PTR を適用するとどちらも同じポインタが返ってきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;RSTRING_PTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;RSTRING_PTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"aaaaaaaaaaaaaaaaaaaaaa"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ここで RSTRING_PTR(s2) で得た C 言語文字列は、s2 の長さ(= 5)で NUL 終端されていません。これが一つ目の罠です。&lt;/p&gt;

&lt;p&gt;そしてこのポインタ値は文字列に対して何らかの操作を行うと変化する可能性があります。たとえば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;s1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"a"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="n"&gt;s2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"b"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;このように文字列の一部を書き換えると、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;RSTRING_PTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"aaaaaaaaaaaaaaaaaaaaaa"&lt;/span&gt;
&lt;span class="n"&gt;RSTRING_PTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"baaaaaaaaaaaaaaaaaaaaa"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;と共有状態が解除されます (注: s2 の長さが変わっていないのは書き間違いではありません！)。Ruby の世界での変更だけではなく、C 言語 API を使って文字列を変更しても、たとえば文字列オブジェクトに C 言語文字列を追加する &lt;code&gt;mrb_str_cat&lt;/code&gt; を使っても、共有状態が解除されます。共有状態が解除された後でもう一度 RSTRING_PTR を使えば正しいポインタ値を得ることができますが、何をした時に共有状態が解除されポインタ値が動くかが自明ではないので、しばしば忘れられます。これが二つ目の罠です。&lt;/p&gt;

&lt;p&gt;最後に RSTRING_PTR の良い点を挙げると、NUL 文字が含まれた Ruby 文字列を適切に取り扱えるのはこの API だけです。mrb_string_value_cstr と mrb_str_to_cstr はどちらも NUL 終端された C 言語文字列を返します。すなわち、API の仕様上 NUL 文字を含むようなバイト列は取り扱えません。したがって、NUL 文字を含むようなバイナリ文字列を扱う場合は RSTRING_PTR 一択となります。&lt;/p&gt;

&lt;h2&gt;
  
  
  mrb_string_value_cstr
&lt;/h2&gt;

&lt;p&gt;mrb_string_value_cstr は癖の強い API です。呼び出し規約はこうなっています:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mrb_string_value_cstr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb_state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mrb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mrb_value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;動作としては、&lt;code&gt;*ptr&lt;/code&gt; が示す Ruby 文字列の、C 言語文字列(バイト列)を示すポインタを返します。返ってきたポインタは Ruby 文字列の長さ(バイト数)で NUL 終端されていることが保証されます。NUL 終端が保証されている分 RSTRING_PTR より使いやすくなっていますが、それでもいくつか罠があります。&lt;/p&gt;

&lt;p&gt;まず引数の &lt;code&gt;ptr&lt;/code&gt; がポインタになっているところに違和感を覚えるでしょう。これは &lt;code&gt;*ptr&lt;/code&gt; が String オブジェクトではない時に &lt;code&gt;#to_str&lt;/code&gt; や &lt;code&gt;#to_s&lt;/code&gt; メソッドを呼び出して String オブジェクトを生成し、&lt;code&gt;*ptr&lt;/code&gt; に新しく生成した String オブジェクトを入れて返すという動作をするためです。C 言語文字列を取り出したいだけなのにオブジェクトがすげ変わる可能性があるというのが、まず第一の注意点です。&lt;/p&gt;

&lt;p&gt;次に、struct RString が保持しているバイト列へのポインタを返すという点は RSTRING_PTR と同じですので、ふとした拍子に共有状態が外れてポインタ値が変化するという動作も同じです。これが二つ目の注意点です。&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;del&gt;最後に、&lt;code&gt;#freeze&lt;/code&gt; された文字列に対して mrb_string_value_cstr を呼ぶと、例外が発生する可能性があります。mrb_string_value_cstr は NUL 終端された C 言語文字列を作るために適宜共有状態の解除を行いますが、この処理は文字列への変更処理に該当するため、&lt;code&gt;#freeze&lt;/code&gt; されたオブジェクトに対しては適用できず、例外が上がってしまいます。&lt;/del&gt; (追記) mruby 1.2.0 リリース時点ではこのような挙動をしていましたが、master では(コメントいただいた通り :smiley: )修正されています。&lt;/p&gt;
&lt;h2&gt;
  
  
  mrb_str_to_cstr
&lt;/h2&gt;

&lt;p&gt;mrb_str_to_cstr は文字列のバイト列のコピーを作って、それのポインタを返します。Ruby 文字列を引数に取れる strdup(3) といったところでしょうか。呼び出し規約は以下の通りです:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;mrb_str_to_cstr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb_state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mrb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mrb_value&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;先述の二つの API とは違いコピーを作るため、効率は落ちますが安全に使いやすいバイト列が得られます。得た C 言語文字列は、適切に NUL 終端されていることが保証されます。また、コピーなので書き換えても Ruby 文字列には影響しません。&lt;code&gt;const char *&lt;/code&gt; ではなく &lt;code&gt;char *&lt;/code&gt; を要求するようなライブラリ関数にもそのまま渡すことができます。&lt;/p&gt;

&lt;p&gt;そして、返ってきたポインタは free(3) する必要はなく GC で自動的に回収されます。そのカラクリは、arena 以外のどこからも参照されていない文字列オブジェクトです。&lt;code&gt;mrb_str_to_cstr&lt;/code&gt; は、内部で新しい文字列オブジェクトを生成します。内容は引数の str と同じものです。しかし内部のバイト列は(str と共有するのではなく)別途新たに確保されています。したがって、str に変更があっても影響を受けませんし、逆に新しく作った文字列オブジェクトを変更しても str には影響しません。そして、新しい文字列オブジェクトは arena に置かれているため arena のインデックスが戻るまでは GC に回収されません。通常は Ruby VM の実行ループに戻るまでは arena のインデックスが戻ることはありませんから、C 言語のスコープ内では安全に使えます。&lt;/p&gt;

&lt;h2&gt;
  
  
  結局どれを使えばいいのか？
&lt;/h2&gt;

&lt;p&gt;おすすめは、&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;基本的に &lt;code&gt;mrb_str_to_cstr&lt;/code&gt; を使う。&lt;/li&gt;
&lt;li&gt;メモリアロケーションのコストを避けたいビジーループの中や、NUL 文字を含む文字列を扱う場合は、&lt;code&gt;RSTRING_PTR&lt;/code&gt; と &lt;code&gt;RSTRING_LEN&lt;/code&gt; を使ってバイナリバイト列として処理する。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;です。&lt;code&gt;mrb_string_value_cstr&lt;/code&gt; は癖が強く使いどころが難しいように思います。&lt;/p&gt;

</description>
      <category>mruby</category>
    </item>
    <item>
      <title>mruby で C 言語の構造体をラップしたオブジェクトを作る正しい方法</title>
      <dc:creator>Tomoyuki Sahara</dc:creator>
      <pubDate>Wed, 01 Apr 2020 10:18:39 +0000</pubDate>
      <link>https://dev.to/tsahara/mruby-c-c5g</link>
      <guid>https://dev.to/tsahara/mruby-c-c5g</guid>
      <description>&lt;p&gt;&lt;strong&gt;注: この記事は 2013 年に執筆し、2017 年に最後に更新したものです。&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  mruby で C 言語の構造体をラップしたオブジェクトを作る正しい方法
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;※ この投稿は mruby Advent Calendar 2013 の記事として書かれたものを、内容を mruby 1.3.0 に合わせて更新したものです。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;mruby は小さな言語処理系です。それ単体では HTTP 通信や JSON の読み書きはおろか、ファイル I/O すらできません。Ruby の処理系なのに正規表現も使えません。しかし、mrbgem と呼ばれる拡張モジュールを組み込むことで、必要な機能を必要なだけ足してやることができます。&lt;/p&gt;

&lt;p&gt;mrbgem の開発はかんたんです。mrbgem は C と Ruby (mruby) のコードの組み合わせで書くことができます。mruby の既存の機能で実現可能な範囲のコードは Ruby で書き、Ruby では書けないような処理は C で書くことが機能性や保守性の面からは有利です。&lt;/p&gt;

&lt;p&gt;mrbgem の開発においては、既存の C 言語ライブラリが積極的に再利用されています。&lt;a href="https://github.com/mruby/mgem-list"&gt;mgem-list&lt;/a&gt; という mruby の gem のリストをざっと眺めてみても、C 言語のライブラリを利用していないものを探す方が難しいくらいです。&lt;/p&gt;

&lt;p&gt;C 言語のライブラリでは、ライブラリ固有の情報や状態などを C 言語の構造体にパックしてそれを使い回すテクニックがよく使われます。例えば C 言語の標準入出力ライブラリは、ファイルの状態を FILE 構造体として表現します。標準入出力ライブラリの利用者は FILE 構造体の中身を意識することはありませんし、また中身を直接アクセスすることは推奨されません。そして C 言語のコードの中で FILE 構造体をやりとりする場合は、FILE  構造体へのポインタを関数の引数やグローバル変数として受け渡します。C 言語のコードに閉じている場合はそれで事足りますが、mruby の拡張モジュールでは C 言語で書かれたコードと Ruby で書かれたコードを行き来する必要があるため、単にどこかの変数に格納するだけは済みません。&lt;/p&gt;

&lt;p&gt;C 言語のコードと Ruby のコードを行ったり来たりしつつ、C 言語ライブラリを使うための構造体を保持し続けるためには、C 言語ライブラリが要求する構造体に皮をかぶせて Ruby のオブジェクトとしてしまうのが一番シンプルな方法です。mruby では、このようなオブジェクト (適当な名前が無いようなので以下 Data オブジェクトと呼びます) を扱うクラスをたいへん簡単に作ることができます。しかしこれを &lt;strong&gt;正しく&lt;/strong&gt; 使うのは意外とやっかいです。&lt;/p&gt;

&lt;p&gt;この記事では、この Data オブジェクトを正しく扱う方法を、Data オブジェクトを扱う mrbgem を作りながら解説します。&lt;/p&gt;

&lt;h2&gt;
  
  
  mrbgem を作る
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mruby/mruby/blob/master/doc/guides/mrbgems.md"&gt;公式のドキュメント&lt;/a&gt; に従いつつ mrbgem を作ってみます。mrbgem の名前は "mruby-hoge" にします。&lt;/p&gt;

&lt;p&gt;まず mrbgem の名前でディレクトリを作り、その中にソースコードを格納するディレクトリを作ります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% cd mruby
% mkdir mruby-hoge
% mkdir mruby-hoge/src
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;mrbgem をビルドするため、build_config.rb に設定を追記します。必要なビルドターゲットそれぞれに追加してください。典型的には、先頭の &lt;code&gt;MRuby::Build.new&lt;/code&gt; ブロックと、ユニットテストのための &lt;code&gt;MRuby::Build.new('test')&lt;/code&gt; ブロックに追加します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MRuby::Build.new do |conf|
  ...
  conf.gem "#{root}/mruby-hoge"
  ...
end

MRuby::Build.new('test') do |conf|
  ...
  conf.gem "#{root}/mruby-hoge"
  ...
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;続けて mruby-hoge/mrbgem.rake を、&lt;a href="https://github.com/mruby/mruby/blob/master/doc/guides/mrbgems.md#build-process"&gt;テンプレート&lt;/a&gt; からコピーして作ります。ひとまずは名前だけ書き換えれば十分です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MRuby::Gem::Specification.new('mruby-hoge') do |spec|
  spec.license = 'MIT'
  spec.author  = 'mruby developers'
  spec.summary = 'Example mrbgem using C and ruby'
end                                   
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;そして mruby-hoge/src/hoge.c に本体のコードを書きます。まずは何もしないものを置きます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include "mruby.h"

void
mrb_mruby_hoge_gem_init(mrb_state *mrb)
{
}

void
mrb_mruby_hoge_gem_final(mrb_state *mrb)
{
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ここまで書けばコンパイルが通ります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% rake
&lt;/span&gt;&lt;span class="gp"&gt;CC    src/array.c -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;build/host/src/array.o
&lt;span class="gp"&gt;CC    src/backtrace.c -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;build/host/src/backtrace.o
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="gp"&gt;CC    mruby-hoge/src/hoge.c -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;build/host/mrbgems/mruby-hoge/src/hoge.o
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;Build summary:

================================================
      Config Name: host
 Output Directory: build/host
         Binaries: mrbc
    Included Gems:
             mruby-hoge - Example mrbgem using C and ruby
&lt;/span&gt;&lt;span class="c"&gt;             ...
&lt;/span&gt;&lt;span class="go"&gt;%
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;はい、これで何もしない mrbgem ができました。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: mruby の拡張モジュールを C で書く方法については @cubicdaiya さんの &lt;a href="http://qiita.com/cubicdaiya/items/fc0620c7b9629bb85d6f"&gt;mrubyとCの連携&lt;/a&gt; という Post が参考になります。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  構造体をラップしたオブジェクトを作る
&lt;/h2&gt;

&lt;p&gt;さて、準備ができたのでC構造体をラップしたオブジェクトを作ってみます。まずはてきとうにC構造体を用意します。ただしメンバにポインタを含むと話がややこしくなるので、まずはポインタを含まない構造体にしておきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct hoge {
  int num;
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;そしてクラスを定義します。名前は &lt;code&gt;Hoge&lt;/code&gt; にします。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include "mruby/class.h"
#include "mruby/value.h"

void
mrb_mruby_hoge_gem_init(mrb_state *mrb)
{
  struct RClass *cls;

  cls = mrb_define_class(mrb, "Hoge", mrb-&amp;gt;object_class);
  MRB_SET_INSTANCE_TT(cls, MRB_TT_DATA);
  mrb_define_method(mrb, cls, "initialize", mrb_hoge_init, MRB_ARGS_NONE());
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;クラスの作成には &lt;code&gt;mrb_define_class&lt;/code&gt; を使います。この時、親クラスに Object クラスを指定しているのが第一のポイントです。Data クラスは基本的に Object 以外の組み込みクラスの子孫にはできません。ガベージコレクション(GC)のコードが、Data クラスのオブジェクトは Object クラスのオブジェクトと同じメモリレイアウトであると仮定しているためです。&lt;/p&gt;

&lt;p&gt;次に&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="n"&gt;MRB_SET_INSTANCE_TT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MRB_TT_DATA&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;で、いま作ったクラスのインスタンスのデータタイプを MRB_TT_DATA と宣言します。このデータタイプは GC 時の後始末など、オブジェクトの取扱いに影響します。最後に &lt;code&gt;initialize&lt;/code&gt; メソッドを &lt;code&gt;mrb_hoge_init&lt;/code&gt; 関数で定義します。なお、ここまで struct hoge が出てきていませんが、Hoge クラスと struct hoge の紐付けはコンストラクタ &lt;code&gt;mrb_hoge_init&lt;/code&gt; の中で行われます。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: 本稿で作成した mrbgem では、mrbgem の名前と構造体名と関数名にすべて "hoge" を入れています。これは単なる慣例でルールではないため、任意の名前に変えても動きます。ただし mrbgem の名前と mrbgem の初期化/終了関数の名前だけは例外的に強い依存関係があり、ビルドシステムによって &lt;code&gt;mrb_#{mrbgemの名前}_gem_init/final&lt;/code&gt; と決められており変更できません。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;さて、&lt;code&gt;mrb_hoge_init&lt;/code&gt; の中身を書く前にもうひとつ準備をしておきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include "mruby/data.h"

const static struct mrb_data_type mrb_hoge_type = { "Hoge", mrb_free };
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;struct mrb_data_type 型の変数 &lt;code&gt;mrb_hoge_type&lt;/code&gt; を定義します。struct mrb_data_type は、Data オブジェクトが GC で回収される時に後始末をする関数を定義するためのデータ構造です。struct mrb_data_type の定義は mruby/data.h にあります:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;22 typedef struct mrb_data_type {
23   /** data type name */
24   const char *struct_name;
25 
26   /** data type release function pointer */
27   void (*dfree)(mrb_state *mrb, void*);
28 } mrb_data_type;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;struct_name&lt;/code&gt; は例外のメッセージとして表示するためにしか使われないため適当で構いません。そのクラスの名前を書くのが慣例です。一方もうひとつのメンバ &lt;code&gt;dfree&lt;/code&gt; は重要です。&lt;code&gt;dfree&lt;/code&gt; は関数ポインタで、その関数は Data オブジェクトが GC によって到達不能(=ゴミ)と判定された時に呼ばれ、malloc した領域やファイルデスクリプタの解放などのオブジェクトの後始末を行います。&lt;/p&gt;

&lt;p&gt;さて Hoge クラスの mrb_data_type を改めて見てみます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;mrb_data_type&lt;/span&gt; &lt;span class="n"&gt;mrb_hoge_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Hoge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mrb_free&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;mrb_hoge_type は変更する必要がないため const で宣言しています。はじめのメンバ &lt;code&gt;struct_name&lt;/code&gt; は慣例に従ってクラスの名前と同じ "Hoge" としました。そして &lt;code&gt;dfree&lt;/code&gt; には mruby のメモリ管理 API をそのまま使って mrb_free を設定しました。後述のように構造体の領域を mrb_malloc を使って確保する Data オブジェクトで、また構造体メンバにポインタなどの解放が必要なリソースを含まない場合は mrb_free を設定しておけば十分です。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: ポインタを含まなくても、ファイルデスクリプタ等の解放処理が必要なリソースを含む場合はカスタム &lt;code&gt;dfree&lt;/code&gt; を用意する必要があります。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;準備ができたので &lt;code&gt;mrb_hoge_init&lt;/code&gt; を書きます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mrb_value
mrb_hoge_init(mrb_state *mrb, mrb_value self)
{
  struct hoge *h;

  h = (struct hoge *)mrb_malloc(mrb, sizeof(struct hoge));
  h-&amp;gt;num = 1234;
  DATA_TYPE(self) = &amp;amp;mrb_hoge_type;
  DATA_PTR(self) = h;
  return self;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;一行づつ見てゆきます。&lt;/p&gt;

&lt;p&gt;まず mrb_malloc で構造体のデータ領域を確保します。mrb_malloc は malloc(3) と同じように動きますが、 &lt;strong&gt;例外を上げる可能性がある&lt;/strong&gt; 点が大きな違いです。 &lt;strong&gt;例外を上げる可能性があります。&lt;/strong&gt; ここ重要です。そして確保した &lt;code&gt;h&lt;/code&gt; に適当に値をセットします。ここではメンバ &lt;code&gt;num&lt;/code&gt; に 1234 でも入れておきます。&lt;br&gt;
次に&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="n"&gt;DATA_TYPE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mrb_hoge_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;で &lt;code&gt;self&lt;/code&gt; のデータ型を mrb_hoge_type に設定し、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="n"&gt;DATA_PTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;でいま確保したデータ構造のポインタを &lt;code&gt;self&lt;/code&gt; にセットします。ここまでで C 構造体をラップしたオブジェクトを作ることができるようになりました。&lt;/p&gt;

&lt;h2&gt;
  
  
  構造体の中身の参照
&lt;/h2&gt;

&lt;p&gt;さきほどオブジェクトにポインタをセットするのに使った &lt;code&gt;DATA_PTR&lt;/code&gt; は、反対にラップされたオブジェクトからポインタを取り出すことにも使えます。これを利用して値を取り出すメソッドを足してみます。&lt;/p&gt;

&lt;p&gt;まず Hoge クラスにメソッドを定義します。名前はベタに &lt;code&gt;#get&lt;/code&gt; メソッドとしておきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void
mrb_mruby_hoge_gem_init(mrb_state *mrb)
{
  ...
  mrb_define_method(mrb, cls, "get", mrb_hoge_get, MRB_ARGS_NONE());
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;#get&lt;/code&gt; メソッドの実装 &lt;code&gt;mrb_hoge_get&lt;/code&gt; では、メンバ変数 &lt;code&gt;num&lt;/code&gt; の値を Ruby オブジェクトに変換して返します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mrb_value
mrb_hoge_get(mrb_state *mrb, mrb_value self)
{
  struct hoge *h;

  h = DATA_PTR(self);
  return mrb_fixnum_value(h-&amp;gt;num);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;いったん DATA_PTR でポインタを取り出せば、あとは通常の構造体ポインタとしてアクセスできます。ここでは &lt;code&gt;h-&amp;gt;num&lt;/code&gt; の値を &lt;code&gt;mrb_fixnum_value&lt;/code&gt; 関数を使って Ruby の Fixnum オブジェクトに変換してリターンします。コンパイルして動かしてみましょう。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% rake 
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;% bin/mruby -e 'a = Hoge.new;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;p a.get&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;span class="go"&gt;1234
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;はい、バッチリですね。get を作ったので続けて put も作ってみます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;mrb_value&lt;/span&gt;
&lt;span class="nf"&gt;mrb_hoge_put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb_state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mrb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mrb_value&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;hoge&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;mrb_int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;mrb_get_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"i"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DATA_PTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mrb_fixnum_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;mrb_mruby_hoge_gem_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb_state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mrb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="n"&gt;mrb_define_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"put"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mrb_hoge_put&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MRB_ARGS_REQ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;こちらはどうでしょうか。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;% bin/mruby -e 'a = Hoge.new;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;a.put&lt;span class="o"&gt;(&lt;/span&gt;3&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; p a.get&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;span class="go"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;うまく動いていますね。Hoge は Object クラスを継承しているので、Object クラスのメソッドもふつうに使え...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;% bin/mruby -e 'a = Hoge.new;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;p a.object_id&lt;span class="p"&gt;;&lt;/span&gt; p a.nil?&lt;span class="p"&gt;;&lt;/span&gt; p a.dup.get&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;span class="go"&gt;1907878821
false
&lt;/span&gt;&lt;span class="gp"&gt;zsh: segmentation fault (core dumped)  bin/mruby -e 'a = Hoge.new;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;p a.object_id&lt;span class="p"&gt;;&lt;/span&gt; p a.nil?&lt;span class="p"&gt;;&lt;/span&gt; p a.dup.get&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;おや?&lt;/p&gt;

&lt;h2&gt;
  
  
  #dup
&lt;/h2&gt;

&lt;p&gt;segmentation fault が発生した原因を探ってみます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;% bin/mruby -e 'a = Hoge.new;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;a.dup&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;span class="gp"&gt;% bin/mruby -e 'a = Hoge.new;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;a.dup.get'&lt;/span&gt;
&lt;span class="gp"&gt;zsh: segmentation fault (core dumped)  bin/mruby -e 'a = Hoge.new;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;a.dup.get&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;#dup&lt;/code&gt; しただけなら大丈夫です。その後で &lt;code&gt;#get&lt;/code&gt; を呼ぶと死にます。デバッガで追ってみます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% gdb bin/mruby mruby.core
GNU gdb 6.3
...
Core was generated by `mruby'.
Program terminated with signal 11, Segmentation fault.
...
#0  0x0000074c0656528b in mrb_hoge_get (mrb=0x74eb1ca8600, self=
      {value = {f = 3.9684672274376703e-311, p = 0x74e286d38b0, i = 678246576, s
ym = 678246576}, tt = MRB_TT_DATA})
    at /home/tsahara/src/mruby/mruby-hoge/src/hoge.c:30
30        return mrb_fixnum_value(h-&amp;gt;num);
(gdb)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;mrb_fixnum_value&lt;/code&gt; 関数を使って &lt;code&gt;h-&amp;gt;num&lt;/code&gt; の値を Ruby のオブジェクトに変換しているところで死んでいます。まずはポインタ変数 &lt;code&gt;h&lt;/code&gt; の値を見てみます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) p h
$1 = (struct hoge *) 0x0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;はい、NULL が入っていました。原因はこれですね。&lt;/p&gt;

&lt;p&gt;では &lt;code&gt;DATA_PTR(self)&lt;/code&gt; がなぜ NULL なのでしょうか。答えはかんたんで、誰も設定していないからです。&lt;code&gt;Hoge#dup&lt;/code&gt; の実体は Object クラスの &lt;code&gt;#dup&lt;/code&gt; メソッドです。しかし Object クラスのメソッドは子クラス側で &lt;code&gt;DATA_PTR(self)&lt;/code&gt; を使っているなんて知りません。したがってここは子クラス側で面倒を見てやる必要があります。&lt;/p&gt;

&lt;p&gt;Ruby (MRI) では、&lt;code&gt;#dup&lt;/code&gt; メソッド等でオブジェクトのコピーが必要とされた場合には &lt;code&gt;#initialize_copy&lt;/code&gt; が呼ばれます。mruby でも事情は一緒で、Data クラスには &lt;code&gt;#initialize_copy&lt;/code&gt; メソッドを定義する必要があります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static mrb_value
mrb_hoge_init_copy(mrb_state *mrb, mrb_value copy)
{
  mrb_value src;

  mrb_get_args(mrb, "o", &amp;amp;src);
  if (mrb_obj_equal(mrb, copy, src)) return copy;
  if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) {
    mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
  }
  if (!DATA_PTR(copy)) {
    DATA_PTR(copy) = (struct hoge *)mrb_malloc(mrb, sizeof(struct hoge));
    DATA_TYPE(copy) = &amp;amp;mrb_hoge_type;
  }
  *(struct hoge *)DATA_PTR(copy) = *(struct hoge *)DATA_PTR(src);
  return copy;
}

void
mrb_mruby_hoge_gem_init(mrb_state *mrb)
{
  ...
  mrb_define_method(mrb, cls, "initialize_copy", mrb_hoge_init_copy, MRB_ARGS_REQ(1));
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;理解しにくいコードが並んでいますが、注意しなければならないのは最後に構造体をコピーしている個所だけです。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;hoge&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;DATA_PTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;hoge&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;DATA_PTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;あまりお目にかからない構造体の代入構文でまるっとコピーしています。struct hoge にはメンバが &lt;code&gt;num&lt;/code&gt; しかありませんから、やっていることは結局 copy の &lt;code&gt;num&lt;/code&gt; を src の &lt;code&gt;num&lt;/code&gt; にコピーしているだけです。さて、直ったでしょうか。長くなるため今度は mirb で試してみます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mirb&lt;/span&gt;
&lt;span class="n"&gt;mirb&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;Embeddable&lt;/span&gt; &lt;span class="no"&gt;Interactive&lt;/span&gt; &lt;span class="no"&gt;Ruby&lt;/span&gt; &lt;span class="no"&gt;Shell&lt;/span&gt;

&lt;span class="no"&gt;This&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;very&lt;/span&gt; &lt;span class="n"&gt;early&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;please&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="no"&gt;Thanks&lt;/span&gt; &lt;span class="p"&gt;:)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Hoge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Hoge:0xc7678ec9bb0&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dup&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Hoge:0xc7678ec9a60&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;
&lt;span class="mi"&gt;4&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;うまく動いているようです。&lt;/p&gt;

&lt;h2&gt;
  
  
  カスタム dfree
&lt;/h2&gt;

&lt;p&gt;それでは、もう少し複雑な構造体をラップしてみます。例としてファイル構造体 &lt;code&gt;FILE *&lt;/code&gt; にしておきます。まず &lt;code&gt;struct hoge&lt;/code&gt; にメンバ &lt;code&gt;FILE *fp&lt;/code&gt; を足します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

struct hoge {
  int num;
  FILE *fp;
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;次に初期化処理 &lt;code&gt;mrb_hoge_init&lt;/code&gt; に fp の初期化を足します。ファイル構造体を持つオブジェクトの初期化なので、コンストラクタ &lt;code&gt;Hoge.new&lt;/code&gt; の引数としてファイル名を取るのが自然でしょう。そのファイルを fopen(3) に渡して、返り値で fp で初期化します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include "mruby/string.h"

mrb_value
mrb_hoge_init(mrb_state *mrb, mrb_value self)
{
  FILE *fp;
  struct hoge *h;
  mrb_value path;
  char *cpath;

  mrb_get_args(mrb, "S", &amp;amp;path);
  cpath = mrb_str_to_cstr(mrb, path);
  fp = fopen(cpath, "r");
  if (fp == NULL) {
    mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot open file: %S", path);
  }

  h = (struct hoge *)mrb_malloc(mrb, sizeof(struct hoge));
  h-&amp;gt;num = 1234;
  h-&amp;gt;fp = fp;
  DATA_TYPE(self) = &amp;amp;mrb_hoge_type;
  DATA_PTR(self) = h;
  return self;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: mrb_str_to_cstr は mruby の String を格納した mrb_value から C 言語の NUL 終端文字列を取り出すユーティリティ関数です。"mruby/string.h" で宣言されています。同様の機能を持つものに RSTRING_PTR マクロがありますが、こちらは適切な長さで NUL 終端されている保証がありません。ちょっと複雑なプログラムを書くと表れるという追い難いバグの原因となるため注意が必要です。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;先に書いておくと、上のコードには &lt;strong&gt;バグがあります。&lt;/strong&gt; が、ひとまず先に解放のコードを書いてしまいましょう。解放する関数の名前は &lt;code&gt;mrb_hoge_free&lt;/code&gt; としておきます。関数プロトタイプは、先述の通り "mruby/data.h" で定義されている&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  void (*dfree)(mrb_state *mrb, void*);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;に合わせます。mrb はおなじみの mrb_state へのポインタで、もうひとつの引数が C 言語構造体のデータを指し示すポインタです。実装はこの通りです:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static void
mrb_hoge_free(mrb_state *mrb, void *ptr)
{
  struct hoge *h = ptr;

  fclose(h-&amp;gt;fp);
  mrb_free(mrb, h);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;まずC 言語構造体のデータオブジェクトが持つリソース &lt;code&gt;h-&amp;gt;fp&lt;/code&gt; を解放し、それからデータオブジェクトそのもの &lt;code&gt;h&lt;/code&gt; を解放します。そして  mrb_hoge_type の dfree をいま定義した mrb_hoge_free 関数で置き換えます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;mrb_data_type&lt;/span&gt; &lt;span class="n"&gt;mrb_hoge_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Hoge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mrb_hoge_free&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;それでは新しく追加した fp を使うメソッドを追加してみます。ファイルの内容を読み出す &lt;code&gt;#read&lt;/code&gt; メソッドにします。きちんと機能するものを作るのは少々面倒なので「ファイルの先頭の方をたいてい読み出せる」メソッドにします。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mrb_value
mrb_hoge_read(mrb_state *mrb, mrb_value self)
{
  struct hoge *h;
  size_t n;
  char buf[1024];

  h = DATA_PTR(self);
  n = fread(buf, 1, sizeof(buf), h-&amp;gt;fp);
  if (n == 0) {
    mrb_raise(mrb, E_ARGUMENT_ERROR, "fread(3) returns 0");
  }
  return mrb_str_new(mrb, buf, n);
}

void
mrb_mruby_hoge_gem_init(mrb_state *mrb)
{
  ...
  mrb_define_method(mrb, cls, "read", mrb_hoge_read, MRB_ARGS_NONE());
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;細かいことは気にせず fread(3) で 1024 バイトを読み出してみて、それを mruby の String オブジェクトにして返すことにしました。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% rake
&lt;/span&gt;&lt;span class="gp"&gt;% bin/mruby -e 'h = Hoge.new("mruby-hoge/mrbgem.rake");&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;puts h.read&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;span class="go"&gt;MRuby::Gem::Specification.new('mruby-hoge') do |spec|
  spec.license = 'MIT'
  spec.author  = 'mruby developers'
  spec.summary = 'Example mrbgem using C and ruby'
end
%
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;意図した通りに機能しているようです。&lt;/p&gt;

&lt;h2&gt;
  
  
  リソースの解放タイミング
&lt;/h2&gt;

&lt;p&gt;残念ながら、現在の実装は大きなスクリプトで利用すると期待通りにうまく動きません。Hoge.new を何回も呼ぶと失敗する可能性があります:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% bin/mruby -e '10000.times { Hoge.new("mruby-hoge/mrbgem.rake") }'
trace:
        [0] -e:1
        [1] /home/tsahara/src/mruby/mrblib/numeric.rb:77:in times
        [2] -e:1:in call
-e:1: cannot open file: mruby-hoge/mrbgem.rake (ArgumentError)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;繰り返しの回数をたとえば 10 回程度に減らしてやると動作します。回数が多くなると動かなくなります。原因は少々わかりにくいのですが、ファイルデスクリプタの不足が発生しています。&lt;code&gt;ulimit -n 20&lt;/code&gt; 等としてリミットを小さくしてやると、ループの回数との相関が見てとれます。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: &lt;a href="https://github.com/iij/mruby-errno"&gt;iij/mruby-errno&lt;/a&gt; を利用すると例外オブジェクトを介してもう少し詳細なエラーを取得できるため、システムコールを叩くような mrbgem のデバッグが楽になります。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;でも、さきほど確かにファイル構造体を解放(fclose)する mrb_hoge_free を書きました。これが正しく呼ばれていないのでしょうか。&lt;/p&gt;

&lt;p&gt;ポイントは mrb_hoge_free が呼ばれるタイミングにあります。mrb_hoge_free、一般化して dfree は Data オブジェクトが解放されるタイミングで呼ばれます。そして mruby ではオブジェクトが解放されるタイミングは GC が決めます。GC がオブジェクトを解放するタイミング... はややこしいので説明を省略しますが、ループから抜けた時に GC が走らない(ことがある)点がポイントです。そのために、ループ内で作成した Hoge オブジェクトはすぐには解放されず、その結果 Hoge オブジェクトが保持する FILE 構造体もクローズされず、プロセスのリミットに逹したところで fopen(3) が失敗し始めます。&lt;/p&gt;

&lt;p&gt;この問題の対処は確保したリソースの特性にもよっていろいろ考えられます。今回は Ruby の MRI 実装 や &lt;a href="https://github.com/iij/mruby-io"&gt;iij/mruby-io&lt;/a&gt; で行われている対処を入れてみます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...
  fp = fopen(cpath, "r");
  if (fp == NULL) {
    if (errno == EMFILE || errno == ENFILE) {
      mrb_full_gc(mrb);
      fp = fopen(cpath, "r");
    }
    if (fp == NULL) {
      mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot open file: %S", path);
    }
  }

  h = (struct hoge *)mrb_malloc(mrb, sizeof(struct hoge));
  ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;fopen(3) に失敗し、その原因がファイルデスクリプタ溢れだった場合は強制的に Full GC を走らせ、宙に浮いている Hoge オブジェクトがあればそれを回収することによって間接的に mrb_hoge_free を呼び、不要な FILE 構造体を fclose(3) するようにしました。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% bin/mruby -e '10000.times { Hoge.new("mruby-hoge/mrbgem.rake") }'
%
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;この通り動くようになりました。&lt;/p&gt;

&lt;h2&gt;
  
  
  リソースの設定順序
&lt;/h2&gt;

&lt;p&gt;先に "カスタム dfree" の節でも書きましたが、現在の mrb_hoge_init の実装には &lt;strong&gt;バグがあります。&lt;/strong&gt; mrb_hoge_init を再掲します。バグは FILE 構造体のリークです。どういうロジックで起こり得るかわかりますか?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mrb_value
mrb_hoge_init(mrb_state *mrb, mrb_value self)
{
  FILE *fp;
  struct hoge *h;
  mrb_value path;
  char *cpath;

  mrb_get_args(mrb, "S", &amp;amp;path);
  cpath = mrb_str_to_cstr(mrb, path);
  fp = fopen(cpath, "r");
  if (fp == NULL) {
    if (errno == EMFILE || errno == ENFILE) {
      mrb_full_gc(mrb);
      fp = fopen(cpath, "r");
    }
    if (fp == NULL) {
      mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot open file: %S", path);
    }
  }

  h = (struct hoge *)mrb_malloc(mrb, sizeof(struct hoge));
  h-&amp;gt;num = 1234;
  h-&amp;gt;fp = fp;
  DATA_TYPE(self) = &amp;amp;mrb_hoge_type;
  DATA_PTR(self) = h;
  return self;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;答えは mrb_malloc の呼び出しです。この位置で呼んではいけません。&lt;/p&gt;

&lt;p&gt;C プログラマならぱっと見て、「NULL チェックしてないな」と気づくでしょう。しかしそれではありません(NULL チェックは必要と言えば必要ですが... 話が長くなるため割愛します)。実は、mrb_malloc は &lt;strong&gt;例外を発生し longjmp(3) を使って一足飛びに mrb_hoge_init から抜け出してしまうことがあります。&lt;/strong&gt; ここの位置で抜け出されると、直前に開いた fp がコールスタックから消えさり解放しようが無くなります。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: どんな例外をどんな場合に上げるか興味のある方は &lt;a href="https://github.com/mruby/mruby/blob/master/src/gc.c"&gt;src/gc.c&lt;/a&gt; からたどってください。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;このバグはコマンドラインから mruby コマンドを実行するようなケースではほとんど問題にならないでしょう。しかし外部のプログラムに libmruby をリンクし、カスタムメモリアロケータ(&lt;code&gt;mrb-&amp;gt;allocf&lt;/code&gt;)を使ってメモリ容量に上限を設けておくようなケースでは、mruby 内でのリソースリークが組み込み先のプログラムを殺すことになります。&lt;/p&gt;

&lt;p&gt;この問題はいくつかの方法で回避が可能です。今回のケースでは mrb_malloc の呼び出しを fopen の直前に持ってくるのがいちばん簡単です。しかしひとつの構造体の中に確保/解放が必要なリソースが複数あったり、また初期化関数の中で mrb_malloc() 以外の例外を発生させうる関数を呼ぶようなケースではとたんに難しくなります。よって、ここではもう少し一般的な方法を紹介します。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: 「例外を発生させうる関数」というのが曲者です。mruby の多種多様な API のうち、どの関数が例外を発生し得るかはその関数の実装をたんねんに追ってゆかないとわかりません。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;まず mrb_malloc() による構造体のアロケートと DATA_TYPE/DATA_PTR のセットを先頭に持ってきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...
  char *cpath;

  h = (struct hoge *)mrb_malloc(mrb, sizeof(struct hoge));
  DATA_TYPE(self) = &amp;amp;mrb_hoge_type;
  DATA_PTR(self) = h;

  mrb_get_args(mrb, "S", &amp;amp;path);
  ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;これなら mrb_malloc() が例外を上げてもリークするリソースは何もありません。そして mrb_get_args の呼び出し以降で例外が上がっても(あるいは return で抜けても)、self には DATA_TYPE で GC 用の構造が設定済みですから、mrb_malloc() で確保した DATA_PTR(self) = h はいずれ GC によって解放されます。ただしこのままでは &lt;code&gt;h-&amp;gt;fp&lt;/code&gt; が初期化されないまま mrb_hoge_free が呼ばれる可能性があります。解放前は NULL で初期化しておくことにしましょう。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...
  h = (struct hoge *)mrb_malloc(mrb, sizeof(struct hoge));
  h-&amp;gt;fp = NULL;
  DATA_TYPE(self) = &amp;amp;mrb_hoge_type;
  DATA_PTR(self) = h;
  ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;h-&amp;gt;fp&lt;/code&gt; が NULL の場合でもちゃんと動くように mrb_hoge_free も更新します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static void
mrb_hoge_free(mrb_state *mrb, void *ptr)
{
  struct hoge *h = ptr;

  if (h-&amp;gt;fp != NULL) {
    fclose(h-&amp;gt;fp);
    h-&amp;gt;fp = NULL;
  }
  mrb_free(mrb, h);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;このように mrb_malloc() で C 言語構造体をまずはじめに確保し、例外が発生しないことが担保されている間に NULL や -1 といった確保していないことを意味する値で埋めておき、いつどのタイミングで呼ばれてもリソースを適切に解放できるように dfree 関数を書いておくのがリソースリークを避けるコツです。&lt;/p&gt;

&lt;h2&gt;
  
  
  終わりに
&lt;/h2&gt;

&lt;p&gt;本日は mruby で C 言語の構造体をラップしたオブジェクトを正しく取り扱う方法を紹介しました。この他にも、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TCPSocket のような複雑な &lt;code&gt;#initialize&lt;/code&gt; を持つ Data クラスで、&lt;code&gt;#initialize&lt;/code&gt; を Ruby のコードで実装する方法&lt;/li&gt;
&lt;li&gt;Data クラスを継承した時の DATA_TYPE/DATA_PTR の初期化の仕方&lt;/li&gt;
&lt;li&gt;SystemCallError のように &lt;code&gt;.new&lt;/code&gt; の引数によって異なるクラスのオブジェクトを生成するクラスの実装法&lt;/li&gt;
&lt;li&gt;リソースを持つ Data クラスの initialize_copy &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;など取り上げたいネタはありましたが、時間切れとなりましたのでこの記事はここでおしまいです。長い記事にお付き合いいただきありがとうございました。&lt;/p&gt;

</description>
      <category>mruby</category>
    </item>
    <item>
      <title>1.0.0 でも master でも動く mrbgem の書き方</title>
      <dc:creator>Tomoyuki Sahara</dc:creator>
      <pubDate>Wed, 01 Apr 2020 10:12:28 +0000</pubDate>
      <link>https://dev.to/tsahara/1-0-0-master-mrbgem-445p</link>
      <guid>https://dev.to/tsahara/1-0-0-master-mrbgem-445p</guid>
      <description>&lt;p&gt;&lt;strong&gt;注: この記事は 2014/03 に書いたものです。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;mruby の&lt;a href="http://forum.mruby.org/download/index.html"&gt;安定版1.0.0&lt;/a&gt;と&lt;a href="https://github.com/mruby/mruby"&gt;最新版&lt;/a&gt;のどちらでも動作する mrbgem の書き方を紹介します。以下では、安定版のことを 1.0.0、最新版のことを master と呼びます。&lt;/p&gt;

&lt;h1&gt;
  
  
  C 言語 API の変更
&lt;/h1&gt;

&lt;h2&gt;
  
  
  mrb_str_cat_lit の追加
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;mrb_str_cat_lit&lt;/code&gt; の動作は &lt;code&gt;mrb_str_cat_cstr&lt;/code&gt; と同じです。strlen(3) 一回分速いだけの違いしかありませんから、&lt;code&gt;mrb_str_cat_cstr&lt;/code&gt; を使っておけば間違いありません。&lt;/p&gt;

&lt;h2&gt;
  
  
  mrb_const_defined_at の引数の型の変更
&lt;/h2&gt;

&lt;p&gt;返り値と第二引数の型が異なります。第二引数の型は &lt;code&gt;mrb_value&lt;/code&gt; と &lt;code&gt;struct RClass *&lt;/code&gt; でまったく異なるため注意が必要です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* master */&lt;/span&gt; &lt;span class="n"&gt;mrb_bool&lt;/span&gt; &lt;span class="nf"&gt;mrb_const_defined_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb_state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mrb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mrb_value&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mrb_sym&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cm"&gt;/* 1.0.0  */&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;mrb_const_defined_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb_state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mrb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;RClass&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mrb_sym&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  mrb_class_get の仕様変更
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;mrb_module_get&lt;/code&gt; は 1.0.0 と master の違いの中でもっともひっかかりやすいものです。1.0.0 では &lt;code&gt;mrb_class_get&lt;/code&gt; の引数としてクラスもモジュールもどちらも指定できましたが、master ではクラスしか指定できなくなりました。モジュールを得るためには替わりに &lt;code&gt;mrb_module_get&lt;/code&gt; を使う必要があります。重要な非互換ですが、対応は容易です。1.0.0 では &lt;code&gt;mrb_module_get&lt;/code&gt; は以下のように定義できます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if MRUBY_RELEASE_NO &amp;lt; 10000
&lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;RClass&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;mrb_module_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb_state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mrb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mrb_class_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mrb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;例: &lt;a href="https://github.com/iij/mruby-io/blob/master/src/io.c#L23"&gt;https://github.com/iij/mruby-io/blob/master/src/io.c#L23&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  mrb_yield_internal の名称変更
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;mrb_yield_internal&lt;/code&gt; は 1.0.0 では非公開な API という位置付けでしたが、便利なためいくつかの mrbgem から利用されていました。master では &lt;code&gt;mrb_yield_with_class&lt;/code&gt; と名前を変え、mruby.h で公開されるようになりました。&lt;/p&gt;

&lt;h1&gt;
  
  
  Ruby 言語処理系としての動作の変更
&lt;/h1&gt;

&lt;h2&gt;
  
  
  const_defined? の変更
&lt;/h2&gt;

&lt;p&gt;トップレベルで定義されているモジュール/クラスの名前を Module#const_defined? に与えると、master では true が返ってきます。これは CRuby と同じ挙動です。1.0.0 では false を返してきました。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;const_defined?&lt;/span&gt; &lt;span class="ss"&gt;:A&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;const_get&lt;/span&gt; &lt;span class="ss"&gt;:A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% mruby a.rb
true
A

% mruby-1.0.0 a.rb
false
A
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Float#nan? の追加
&lt;/h2&gt;

&lt;p&gt;Float#nan? は master にはありますが 1.0.0 にはありません。以下のように実装できます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_defined?&lt;/span&gt; &lt;span class="ss"&gt;:nan?&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;nan?&lt;/span&gt;
      &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;例: &lt;a href="https://github.com/iij/mruby-iijson/blob/master/mrblib/json.rb#L104"&gt;https://github.com/iij/mruby-iijson/blob/master/mrblib/json.rb#L104&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Integer#div の追加
&lt;/h2&gt;

&lt;p&gt;Integer#div は master にはありますが 1.0.0 にはありません。以下のように実装できます。あるいは、1.0.0 にもある &lt;code&gt;Integer#divmod&lt;/code&gt; を使って回避することも可能です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_defined?&lt;/span&gt; &lt;span class="ss"&gt;:div&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;divmod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;または &lt;code&gt;123.div(45)&lt;/code&gt; =&amp;gt; &lt;code&gt;123.divmod(45)[0]&lt;/code&gt;&lt;/p&gt;

</description>
      <category>mruby</category>
    </item>
  </channel>
</rss>
