Передача указателя на указатель в Perl 6 NativeCall

Я пытаюсь использовать NativeCall для взаимодействия с некоторыми функциями Си.

В одном случае мне нужно передать указатели, которые обновляются функцией, поэтому ей нужен указатель на указатель 'void **'.

Я попробовал это так:

class Foo
{
    has Pointer $.first;
    has Pointer $.last;

    sub somefunc(Pointer is rw, Pointer is rw, Str) is native { * }

    method myfunc(Str $arg) {
        somefunc($!first, $!last, $arg);
    }
}

Не работает Указатели не обновляются функцией.

Поскольку массив C в основном является указателем на указатель, я могу подделать его следующим образом:

class Foo
{
    has Pointer $.first;
    has Pointer $.last;

    sub somefunc(CArray[Pointer], CArray[Pointer], Str) is native { * }

    method myfunc(Str $arg) {
        my $first = CArray[Pointer].new($!first);
        my $last = CArray[Pointer].new($!last);
        somefunc($first, $last, $arg);
        $!first = $first[0];
        $!last = $last[0];
    }
}

Это работает нормально, как это. Просто кажется, что "is rw" должен принудительно указывать указатель на указатель, и он должен работать в первую очередь.

Что я делаю неправильно?

2 ответа

Решение

Последний раз я проверял, NativeCall все еще имел некоторые грубые края, которые иногда требуют немного творчества; это может быть одним из таких случаев.

Один из обходных путей, о которых я знаю, - это просто использовать целые числа размером с указатель (в частности, size_t или же ssize_t) в качестве параметров и типов атрибутов на стороне1 Perl6, которые должны работать как положено с is rw,

Преобразование между целыми числами и указателями легко: используйте префикс +, .Int или даже просто присваивание переменной целого типа для преобразования в целое число, и Pointer.new(…) или же nqp::box_i(…, Pointer) для другого направления.

При желании, методы доступа могут быть использованы для автоматизации этого преобразования.


1 если вы пойдете этим путем, определение, такое как constant intptr = ssize_t поможет читабельность

Это работает для меня в версии 2017.09:

class Pdu is repr('CStruct') { ... }

sub snmp_synch_response(Snmp-session, Pdu, Pointer[Pdu] is rw) returns int32 is native("netsnmp") { * };

my $p = Pointer[Pdu].new;
my $status = snmp_synch_response($ss, $pdu, $p);
say $status, "-", $p;

my $resp = $p.deref;
say $resp;
Другие вопросы по тегам