LoginSignup
0
0

More than 5 years have passed since last update.

初めてのnativecast

Last updated at Posted at 2016-12-21

こんにちは、Perl 6アドベントカレンダーの22日目の投稿になります。
昨日は、@magnolia_k_さんの、Perl6の中を覗いてみるでした。
今日はnativecastの使い方を紹介しようと思います。

イントロダクション

example.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "example.h"

#ifdef _WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT extern
#endif

void* load(void* payload) {
    return payload;
}
example.h
#if ! defined(HEADER_EXAMPLE_H)
#define HEADER_EXAMPLE_H

#ifdef __cplusplus
extern "C" {
#endif

void* load(void* payload);

#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif

#endif /* HEADER_EXAMPLE_H */
01-basic.t
use v6;
use Test;
use MyNative;
use NativeCall;
use lib <lib t>;
use CompileTestLib;

compile_test_lib('example');

my sub load(Pointer[void] $payload) returns Pointer[void] is native('./example') { * }

my $a = CArray[int32].new;
$a[0] = 1;
$a[1] = 2;
$a[2] = 3;

my $from-c = load($a); # C言語側に$aを渡したい

done-testing;
  • 下記コマンドで実行してみてください
実行
$ prove -e "perl6 -Ilib" -r -v t/01-basic.t 
  • 下記のようなエラーがでてしまったはずです
Native call expected return type with CPointer representation, but got a CArray (NativeCall::Types::CArray[int32])
  in method CALL-ME at /home/itoyota/.rakudobrew/moar-nom/install/share/perl6/sources/24DD121B5B4774C04A7084827BFAD92199756E03 (NativeCall) line 333
  in block <unit> at t/01-basic.t line 17

load関数が要求している引数の型(i.e. Pointer[void])と違う型(i.e. CArray[int32])を渡しているのだから当然ですね。
nativecastを使ってキャストすれば、このようなエラーを回避することができます。
では実際に使っていきましょう!

Let's try!

  • 01-basic.tを下記のように書き換えて再度実行してみましょう
01-basic.t
use v6;
use Test;
use MyNative;
use NativeCall;
use lib <lib t>;
use CompileTestLib;

compile_test_lib('example');

my sub load(Pointer[void] $payload) returns Pointer[void] is native('./example') { * }

my $a = CArray[int32].new;
$a[0] = 1;
$a[1] = 2;
$a[2] = 3;

my $from-c = load(nativecast(Pointer[void],$a)); # C言語側に$aを渡したい

done-testing;
実行
$ prove -e "perl6 -Ilib" -r -v t/01-basic.t
  • 今度はエラーが出なくなりましたね。
  • これは、CArray[int32]をPointer[void]にきちんとキャストしてからC言語側に渡したからです。
  • では、返ってきた値を使いたかったらどうしたらよいでしょうか。
  • このときもnativecastを使うとよいです。
01-basic.t
use v6;
use Test;
use MyNative;
use NativeCall;
use lib <lib t>;
use CompileTestLib;

compile_test_lib('example');

my sub load(Pointer[void] $payload) returns Pointer[void] is native('./example') { * }


my $a = CArray[int32].new;
$a[0] = 1;
$a[1] = 2;
$a[2] = 3;

my $from-c = load(nativecast(Pointer[void], $a));
my $b = nativecast(CArray[int32], $from-c); # (#1)
is $b[0], 1;
is $b[1], 2;
is $b[2], 3;

done-testing;
  • 上記の例では、load関数が返したPointer[void]CArray[int32]にキャストして、Perl6側で使えるようにしています。
  • では、実行してみましょう
実行
$ prove -e "perl6 -Ilib" -r -v t/01-basic.t 
実行結果
t/01-basic.t .. 
ok 1 - 
ok 2 - 
ok 3 - 
1..3
ok
All tests successful.
  • きちんと$bに値が入っていることが確認できましたね。

以上、Perl 6アドベントカレンダーの22日目の投稿でした。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0