Передача указателя на указатель в 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;