読者です 読者をやめる 読者になる 読者になる

RETVAL経由の AV*, HV*の return

perl xs

'perldoc perlxs'に 'Returning SVs, AVs and HVs through RETVAL'という
項目があって、ここに書いている通りにやると

   sub ret_av {
      ...
      return @array;
   }

   sub ret_hv {
      ...
      return %array;
   }

みたいになるのかなと思って試してみたら違ったということのメモ。

ソース

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

MODULE = HV::Test    PACKAGE = HV::Test
PROTOTYPES: DISABLE

AV*
ret_av()
CODE:
    RETVAL = newAV();
    sv_2mortal((SV*)RETVAL);
    av_push(RETVAL, newSViv(10));
    av_push(RETVAL, newSViv(20));
OUTPUT:
    RETVAL

HV*
ret_hv()
CODE:
    RETVAL = newHV();
    sv_2mortal((SV*)RETVAL);
    hv_store(RETVAL, "name", 4, newSVpv("taro", 4), 0);
    hv_store(RETVAL, "age", 3, newSViv(28), 0);
OUTPUT:
    RETVAL

xsubppの結果

XS(XS_HV__Test_ret_av)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
        AV *    RETVAL;
#line 11 "Test.xs"
        RETVAL = newAV();
        sv_2mortal((SV*)RETVAL);
        av_push(RETVAL, newSViv(10));
        av_push(RETVAL, newSViv(20));
#line 94 "Test.c"
        ST(0) = newRV((SV*)RETVAL);
        sv_2mortal(ST(0));
    }
    XSRETURN(1);
}

XS(XS_HV__Test_ret_hv)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
        HV *    RETVAL;
#line 21 "Test.xs"
        RETVAL = newHV();
        sv_2mortal((SV*)RETVAL);
        hv_store(RETVAL, "name", 4, newSVpv("taro", 4), 0);
        hv_store(RETVAL, "age", 3, newSViv(28), 0);
#line 119 "Test.c"
        ST(0) = newRV((SV*)RETVAL);
        sv_2mortal(ST(0));
    }
    XSRETURN(1);
}

それらの値が newRV(Reference Value)となって返ってくる
コードになっていました。

おわりに

あまり直感的ではないので、明示的にリファレンスとして
返すという風に書いた方がいいかなと思いました。


リファレンスを返す例は 'perldoc perlxstut'の EXAMPLE6が
とてもわかりやすかったので、そちらを見るとよいでしょう。