我正在尝试从 包装read函数unistd.h,但无法让它工作。下面是我有:(文件:read.raku)
use NativeCall;
# ssize_t read(int fd, void *buf, size_t count);
sub c_read(int32 $fd, Pointer $buf is rw, size_t $count --> ssize_t) is native is symbol('read') { * }
my $buf = Buf[byte].new(0 xx 5);
my $pbuf = nativecast(Pointer, $buf);
say c_read(3, $pbuf, 5);
say '---------------------';
say $buf;
Run Code Online (Sandbox Code Playgroud)
我像这样从命令行(bash)测试它:
use NativeCall;
# ssize_t read(int fd, void *buf, size_t count);
sub c_read(int32 $fd, Pointer $buf is rw, size_t $count --> ssize_t) is native is symbol('read') { * }
my $buf = Buf[byte].new(0 xx 5);
my $pbuf = nativecast(Pointer, $buf);
say c_read(3, $pbuf, 5);
say '---------------------';
say $buf;
Run Code Online (Sandbox Code Playgroud)
但我得到:
5
---------------------
Buf[byte]:0x<00 00 00 00 00>
Run Code Online (Sandbox Code Playgroud)
所以看起来从 FD 3 读取的字节没有写入Buf.
我也试过这个:
use NativeCall;
# ssize_t read(int fd, void *buf, size_t count);
sub c_read(int32 $fd, Pointer $buf is rw, size_t $count --> ssize_t) is native is symbol('read') { * }
sub c_malloc(size_t $size --> Pointer) is native is symbol('malloc') { * }
my $pbuf = nativecast(Pointer[byte], c_malloc(5));
say c_read(3, $pbuf, 5);
say '---------------------';
say $pbuf[^5];
Run Code Online (Sandbox Code Playgroud)
但是我遇到了分段错误,我猜是由于使用$pbuf[^5]. 但即使只是$pbuf.deref不给第一个字节读取。
所以我一定是做错了什么或者完全误解了如何使用本机调用。
更新:在更多地玩弄之后,看起来上面第二个片段的问题在于is rw位。这似乎有效:
use NativeCall;
use NativeHelpers::Blob;
sub c_read(int32 $fd, Pointer $buf, size_t $count --> ssize_t) is native is symbol('read') { * }
sub c_malloc(size_t $size --> Pointer) is native is symbol('malloc') { * }
my $pbuf := nativecast(Pointer[byte], c_malloc(5));
say c_read(3, $pbuf, 5);
say '---------------------';
say $pbuf[^5]; # (104 101 108 108 111)
Run Code Online (Sandbox Code Playgroud)
好的,所以问题在于rw赋予Pointer $buf. 我猜这会导致read函数在写入时增加指针,从而在我以后使用它时给出错误的地址。
这是两种情况的工作代码:
use NativeCall;
# ssize_t read(int fd, void *buf, size_t count);
sub c_read(int32 $fd, Pointer $buf, size_t $count --> ssize_t) is native is symbol('read') { * }
# Passing a pointer to a Buf directly:
{
my $buf = Buf[byte].new(0 xx 5);
my $pbuf = nativecast(Pointer[byte], $buf);
say c_read(3, $pbuf, 5);
say '---------------------';
say $buf;
}
# Using malloc also works:
{
sub c_malloc(size_t $size --> Pointer) is native is symbol('malloc') { * }
my $pbuf = nativecast(Pointer[byte], c_malloc(5));
say c_read(3, $pbuf, 5);
say '---------------------';
say $pbuf[^5];
}
Run Code Online (Sandbox Code Playgroud)
像这样测试它:
$ (exec 3< <(echo hello world); perl6 ./read.raku)
5
---------------------
Buf[byte]:0x<68 65 6C 6C 6F>
5
---------------------
(32 119 111 114 108)
Run Code Online (Sandbox Code Playgroud)