Perl - XSでDLLを呼び出す(その8)

今回は複数の実数を足した結果を返すサブルーチンを実装する。

新しいモジュールを準備する

練習がてら、「その3」を参考に新しいExample3モジュールを準備する。

2つの実数を足した結果を返す

引き数で指定された2つの実数を足して、その結果を返すサブルーチンをExample3.xsに実装する。

NV
add_num(a, b)
INPUT:
    NV a;
    NV b;
CODE:
    RETVAL = a + b;
OUTPUT:
    RETVAL

今まで培った知識があれば、上記のadd_numサブルーチンの内容は容易に理解できると思うので、説明は省略する。

テストのために以下のスクリプトを "c:\xs\Example3\TestEx3-1.pl" として保存する。

use ExtUtils::testlib;
use Example3;

print Example3::add_num(1.23, "4.56") . "\n";
print Example3::add_num("78yen", "90yen") . "\n";
print eval {Example3::add_num(1)};
print $@;
print eval {Example3::add_num(2, 3.4, 5.67)};
print $@;

上記を実行した結果は以下の通りである。

5.79
168
Usage: Example3::add_num(a, b) at TestEx3-1.pl line 6.
Usage: Example3::add_num(a, b) at TestEx3-1.pl line 8.

Cファイルの内容はどうだろうか。

XS(XS_Example3_add_num)
{
    dXSARGS;
    if (items != 2)
        Perl_croak(aTHX_ "Usage: Example3::add_num(a, b)");
    {
        NV      a = (NV)SvNV(ST(0));
        NV      b = (NV)SvNV(ST(1));
        NV      RETVAL;
        dXSTARG;
#line 19 "Example3.xs"
        RETVAL = a + b;
#line 138 "Example3.c"
        XSprePUSH; PUSHn((NV)RETVAL);
    }
    XSRETURN(1);
}

STマクロは積まれた引き数をスタックから取り出すために使用することがこれで明確になった。
それ以外には特に目新しいものはない。

複数の実数を足した結果を返す

引き数で指定された複数の実数を足して、その結果を返すサブルーチンをExample3.xsに追加で実装する。

NV
add_nums(...)
PREINIT:
    int i;
CODE:
    RETVAL = 0;
    for (i = 0; i < items; i++) {
        RETVAL += SvNV(ST(i));
    }
OUTPUT:
    RETVAL

引き数が不特定多数の場合、引き数リストには「...」とピリオドを3つ記述する。
サブルーチン内部で使用する変数はPREINITフィールドに定義する。
指定された引き数の個数はitems変数が示す。

テストのために以下のスクリプトを "c:\xs\Example3\TestEx3-2.pl" として保存する。

use ExtUtils::testlib;
use Example3;

print Example3::add_nums(1.23) . "\n";
print Example3::add_nums(4.5, "6.7") . "\n";
print Example3::add_nums("8.9", 0.12, 3.456) . "\n";

上記を実行した結果は以下の通りである。

1.23
11.2
12.476

Cファイルの内容はどうだろうか。

XS(XS_Example3_add_nums)
{
    dXSARGS;
    {
#line 26 "Example3.xs"
        int i;
#line 151 "Example3.c"
        NV      RETVAL;
        dXSTARG;
#line 28 "Example3.xs"
        RETVAL = 0;
        for (i = 0; i < items; i++) {
            RETVAL += SvNV(ST(i));
        }
#line 159 "Example3.c"
        XSprePUSH; PUSHn((NV)RETVAL);
    }
    XSRETURN(1);
}

引き数が不特定多数なので、個数を確認する処理がなくなった。


次回は複数の戻り値を返すサブルーチンを実装して見ようと思う。