Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Ruby C拡張機能の書き方(ステップバイステップ)

C拡張機能を作成すると、CからRubyを操作できます。

Cの速度で最適化したい特定の重要な方法がある場合、またはCライブラリとRubyの間にインターフェイスを作成したい場合は、これが必要になることがあります。

別の方法は、FFIモジュールを使用することです。

C拡張機能の書き方を見つけましょう!

最初のC拡張機能

extconf.rbという名前のファイルを作成します これらの内容で:

require 'mkmf'

create_header
create_makefile 'foobar'

次に、ruby extconf.rbを実行します これにより、いくつかのファイルが作成されます(Makefileextconf.h )。これらのファイルは変更しないでください。

次に、foobar.cを作成します 、この名前はcreate_makefileに由来します extconf.rbの行 。必要に応じて変更できますが、.cと一致する必要があります これが機能するためのファイル名。

foobar.cの内部 これを追加します:

#include "ruby.h"
#include "extconf.h"

void Init_foobar()
{
  // Your C code goes here
}

これは、C拡張機能の基本的なスケルトンです。 extconf.rbで宣言した名前を使用する必要があることに注意してください プラス単語Init_ 。この場合、Init_foobar

これは、makeを実行してコンパイルできます。 、そしてあなたが得るものはso requireを使用してRubyアプリケーションにロードできるファイル 。

CからのRubyメソッドの記述

Rubyコードから呼び出すことができるc関数を作成できます。これが組み込みのクラスとメソッドの仕組みです。

すべてのRubyメソッドはVALUEを返す必要があります 。 VALUE Rubyオブジェクトです。

VALUE rb_return_nil() {
  return Qnil;
}

次に、この関数をRubyクラスまたはモジュールにアタッチする必要があります。新しいクラスを作成することも、既存のクラスを使用することもできます。

ここでモジュールを作成しています

void Init_foobar() {
  VALUE mod = rb_define_module("RubyGuides");

  rb_define_method(mod, "return_nil", rb_return_nil, 0);
}

rb_define_methodを使用できます このモジュールにC関数をアタッチする方法。

議論は

引数 説明 モジュールオブジェクト
mod
“ print_hello” Rubyメソッドの名前
rb_print_hello C関数の名前
0 このメソッドが取る引数の数。変数の引数には-1を使用します

次に、makeを実行します もう一度拡張機能をコンパイルして、次のように試してください:

require 'foobar'

include RubyGuides
print_hello

これで、RubyからC関数を呼び出しました!

CからのRubyハッシュの作成

多くの場合、CからRubyオブジェクトを作成および操作する必要があります。

これは、CAPIを使用して行うことができます。

たとえば、ハッシュを作成してそれにいくつかの要素を追加するには:

VALUE create_hash() {
  hash = rb_hash_new();

  rb_hash_aset(hash, rb_str_new2("test"), INT2FIX(1));
  return hash;
}

ここで注意すべき2つの重要な点は、最初にrb_str_new2 関数、これはRuby文字列を作成します。

次に、INT2FIX マクロ。これは通常の整数をRuby整数に変換します。

ここで、rb_define_methodを使用してこの関数をRubyに公開すると 1つのキーを持つ通常のRubyハッシュを取得します(test )&1の値 。

変更を加えるたびに拡張機能を再コンパイルすることを忘れないでください🙂

文字列の操作

C関数はパラメーターを取ることもできます。

例:

VALUE rb_print_length(VALUE self, VALUE str) {
  if (RB_TYPE_P(str, T_STRING) == 1) {
    return rb_sprintf("String length: %ld", RSTRING_LEN(str));
  }

  return Qnil;
}

void Init_foobar()
{
  rb_define_global_function("print_length", rb_print_length, 1);
}

ここでは、VALUEを使用しています (Rubyオブジェクト)を引数として、RB_TYPE_Pの文字列であることを確認します 大きい。その後、RSTRING_LENを使用して文字列の長さを出力します マクロ。

文字列データへのポインタが必要な場合は、RSTRING_PTRを使用できます。 マクロ。

VALUE rb_print_data(VALUE self, VALUE str) {
  if (RB_TYPE_P(str, T_STRING) == 1) {
    return rb_sprintf("String length: %s", RSTRING_LEN(str));
  }

  return Qnil;
}

また、ここに別のパラメーターselfがあることに注意してください。 、これはメソッド呼び出しを受け取るオブジェクトです。

Stringクラス自体でこのメソッドを定義する場合は、次のようにします。

void Init_foobar()
{
  rb_define_method(rb_cString, "print_length", rb_print_length, 0);
}

概要

RubyプログラムからCのすべての機能にアクセスできるように、RubyのC拡張機能を作成する方法を学びました。また、C関数をRubyに公開する方法と、文字列やハッシュなどのCからのRubyオブジェクトを操作する方法も学びました。

CからRubyと対話するためにさらに多くの関数が必要な場合は、Rubyのソースコードでそれらを見つけてC拡張コードを読む必要があるかもしれません。これは十分に文書化されていないためです。

この記事がお役に立てて面白いと思います。もしそうなら、それをあなたの友人と共有して、彼らもそれを楽しむことができるようにしてください。


  1. Rubyでポートスキャナーを作成する方法

    なぜポートスキャナーを作成したいのですか? ポートスキャナーを作成することは、トランスポート層であるTCPプロトコルの基本を学ぶための優れた方法です。 ほとんどのインターネットプロトコル(HTTPおよびSSHを含む)で使用されます。 Rubyネットワークプログラミングがどのように機能するかを学ぶのも良い練習です。 ポートについて話すことから始めましょう! ポートとは何ですか? ポートについて話すとき、私たちは本当に何について話しているのですか? O.S.の港(オペレーティングシステム)レベルは、プロセスに関連付けられた単なる「ファイル記述子」です。 ファイル記述子 stdoutのよう

  2. Rubyでファイルを読み書きする方法(例付き)

    今日は、Rubyでファイルを読み書きして、コンテンツを抽出し、新しいファイルを作成し、必要な情報を見つける方法を学びます。 これから説明します : コンテンツ 1Rubyでファイルを読み取る方法 2Rubyでファイルに書き込む方法 3つのRubyファイルメソッド 4つのディレクトリ操作 5FileUtilsモジュールの使用方法 6まとめ 6.1関連 やってみましょう! Rubyでファイルを読み取る方法 次のようにRubyでファイルを読み取ることができます: ファイルを開く 、open メソッド。 ファイルを読む 、ファイル全体、行ごと、または特定のバイト数。 ファイルを