Perl Hackers Hub

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

この記事を読むのに必要な時間:およそ 1.5 分

前回の(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へ返すコードが簡単に記述できました。

注1)
もちろんXSでもtypemapを扱えます。

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

WEB+DB PRESS

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

2019年6月24日発売
B5判/160ページ
定価(本体1,480円+税)
ISBN978-4-297-10657-7

  • 特集1
    新機能の数々をコミッターが最速解説!
    詳解Rails 6
    新コンポーネント,複数DB対応,並列テスト,オートロード刷新
  • 特集2
    動的かつ高速!
    はじめてのJulia
    科学技術計算のための新言語
  • 特集3
    見える化大作戦
    進捗,成果,無理/ムダ,個人の気持ち……
  • 一般記事
    Elm入門
    型安全な関数型言語によるフロントエンド開発

著者プロフィール

上川慶(かみかわけい)

1995年,沖縄生まれPerl育ち。2018年に株式会社メルカリへ新卒入社し,現在はメルカリのマイクロサービスを開発している。大好きな言語はPerlとGoであり,特性としてよく沖縄に帰ることが多い。

学生時代は沖縄のPerlユーザーコミュニティであるOkinawa.pmを運営しており,一応今でも中の人の一人。