Perl 6封装sd-bus时三重指针函数调用与解引用问题
Perl 6 封装 sd-bus:三重指针函数的调用与解引用方案
问题背景
我尝试用Perl 6的NativeCall封装systemd的sd-bus库,但在调用带有三重指针的sd_bus_list_names函数时遇到了麻烦——调用后不知道怎么把返回的acquired和activatable变量解引用成Perl 6的数组。
原C函数定义(来自sd-bus.h)
int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable); /* free the results */
最初的NativeCall尝试
我一开始是这么定义函数的,但解引用的时候完全摸不着头绪:
sub sd_bus_list_names(Pointer, Pointer[CArray[Str]] , Pointer[CArray[Str]] ) returns int32 is native('systemd') {*}
解决后的完整测试代码
感谢dwarring的回复,终于搞定了解引用的问题,以下是可运行的测试代码:
use v6; use NativeCall; sub strerror(int32) returns Str is native {*} sub sd_bus_default_system(Pointer is rw) returns int32 is native('systemd') {*} sub sd_bus_unref(Pointer) returns Pointer is native('systemd') {*} sub sd_bus_list_names(Pointer, Pointer[CArray[Str]] is rw, Pointer[CArray[Str]] is rw ) returns int32 is native('systemd') {*} my Pointer $bus .= new; my int32 $error; $error = sd_bus_default_system($bus); if $error < 0 { my Str $ser = strerror(-$error); die "fail, can't test triple pointer, dbus return error $error $ser"; } my Pointer[CArray[Str]] $acq .= new; my Pointer[CArray[Str]] $act .= new; $error = sd_bus_list_names($bus, $acq, $act); # 将 acquired 转换为 Perl 6 数组 my @love6acq; loop (my $i = 0; $acq.deref[$i]; $i++){ @love6acq.push: $acq.deref[$i]; } @love6acq.say; # 将 activatable 转换为 Perl 6 数组 my @love6act; loop (my $i = 0; $act.deref[$i]; $i++){ @love6act.push: $act.deref[$i]; } @love6act.say; sd_bus_unref($bus);
关键要点说明
- 修正NativeCall函数声明:给
Pointer[CArray[Str]]参数加上is rw,因为C函数会把分配好的字符串数组的地址写入你传入的指针变量中,必须允许函数修改这些指针的值。 - 解引用逻辑:通过
$acq.deref拿到底层的CArray[Str],然后循环遍历数组元素直到遇到空字符串(C风格的字符串数组结束标记),把每个元素添加到Perl 6数组里。 - 资源释放:记得调用
sd_bus_unref释放总线句柄,避免内存泄漏(另外注意C函数注释里提到需要free返回的结果,实际使用时别忘了添加对应的内存释放逻辑)。
内容的提问来源于stack exchange,提问作者vbextreme vbextreme
相关产品推荐
相关产品推荐

