Perl Hackers Hub

第53回Cを用いたPerl拡張入門―Inline::Cで体験してみよう!(2)

前回の(1)こちらから。

お試しInline::C

では、基本的なC拡張のための記述を、Inline::Cを用いてPerlのソースコード上で体験してみましょう。

この回では、足し算を行う次のPerlサブルーチンに該当するコードを、Inline::Cを用いて作成します。

my $ret = add(1, 2);
printf "result: %d\n", $ret;

sub add {
    return $_[0] + $_[1];
}

実行結果は次のとおりとなります。

result: 3

上記で定義したPerlのaddサブルーチンで注目すべきポイントとして、以下が挙げられます。

  • 引数を2つ受け取る
  • それらの値を用いて計算した結果を返す

PerlとCの間で値の受け渡しがどう行われるのかを、コードを書いて試してみましょう。

Inline::Cのインストール

Inline::Cは、cpanmを利用している人であれば簡単にインストールできます。

$ cpanm Inline::C

スクリプトで書くHello, World

Inline::Cを用いて、Hello, Worldを出力するCのコードを書いてみましょう。

use Inline C;

greet();

__END__
__C__
void greet() {
  printf("Hello, World\n");
}

今までCを書いたことがある人は、Cの標準的な関数を利用するためにstdio.hなどのヘッダファイルの宣言を記述しないことに違和感を感じるかもしれません。Inline::Cはperl.hなど、Cで拡張するために必要なヘッダファイルを自動的に読み込むので、記述する必要がありません。

上記のコードからわかるように、Inline::Cを用いた場合のそれぞれの言語を記述するセクションは基本的に次のとおりとなります。

use Inline C;

# Perlのコードはここに書く

__END__
__C__

/* C のコードはここに書く */

また、Cのコードを文字列として表現することもできます。次の例ではヒアドキュメントを用いています。

use Inline C => <<'...';
/* C のコードはここに書く */
...

# Perlのコードはここに書く

これらの例で、いずれもCのコードはコンパイル時にロードされます。もし変数に文字列としてCのコードを持たせておき、その変数を用いてロードしたい場合は、BEGINを用いる必要があります

ワンライナーで書くHello, World

Inline::Cはワンライナーでも使用できます。

通常Perlモジュールを扱う場合は、次の書き方が一般的です。

$ perl -Mモジュール名 -e '# Perl のコード'

しかしInline::Cの場合は、スクリプトと同様にuseを使わなければいけません。

$ perl -e 'use Inline C=>q{void greet(){printf("Hello, World\n");}};greet'

CとPerl間のやりとり

本稿では触れませんが、Perlはtypemapと呼ばれる、SVからIVを取り出しintへキャストしてCにその値を渡したり、intからSVを作成してPerlへ渡すといったロジックのマッピングを持っています。それを用いて型の操作を裏側で行うので、いつもどおりのCを書くことができます。

本来ならCのコードを書く際にSVの値を直接操作して整数値を取り出すなどしないといけないのですが、Inline::Cを使うとtypemapを用いて自動的に変換してくれます[1]⁠。

Perlの値をCへ渡す

本節の冒頭で挙げた足し算を行うコードをCで実装するには、引数をPerlからCへと渡す必要があります。次のようなコードでPerlからCに引数を渡せます。

use Inline C;

add(1, 2);

__DATA__
__C__
void add(int i, int j) {
  int add = i + j;
  printf("result: %d\n", add); /* result: 3 と表示 */
}

Perl側ではいつもどおりサブルーチンへ引数を渡しています。Cのコードでも普段どおりに、int型の引数を2つ受け取って足し算を行った結果を出力する関数を定義しています。

Cの値をPerlへ渡す

Cのコードで生成した値をPerlの世界でも扱いたいはずです。Cで生成した値をPerlの世界へ渡してみましょう。ここでも特別に難しい考えは必要としません。

先ほど記述した引数のコードを少し修正して、戻り値を返すコードを記述します。

use Inline C;

my $ret = add(1, 2); # 戻り値を変数へ渡す
printf "result: %d\n", $ret; # result: 3 と表示

__DATA__
__C__
int add(int i, int j) {
  return i + j; /* 足し算した結果を返す */
}

Cの関数が値を返すように修正しただけで、処理の結果をPerlへ返すコードが簡単に記述できました。

<続きの(3)こちら。>

WEB+DB PRESS

本誌最新号をチェック!
WEB+DB PRESS Vol.130

2022年8月24日発売
B5判/168ページ
定価1,628円
(本体1,480円+税10%)
ISBN978-4-297-13000-8

  • 特集1
    イミュータブルデータモデルで始める
    実践データモデリング

    業務の複雑さをシンプルに表現!
  • 特集2
    いまはじめるFlutter
    iOS/Android両対応アプリを開発してみよう
  • 特集3
    作って学ぶWeb3
    ブロックチェーン、スマートコントラクト、NFT

おすすめ記事

記事・ニュース一覧