【问题标题】:Getting data out of Native pointers从本机指针中获取数据
【发布时间】:2018-06-28 11:13:35
【问题描述】:

将数据放入 Perl 6 Native 指针中没什么大不了的:

sub memcpy( Pointer[void] $source, Pointer[void] $destination, int32 $size ) is native { * };
my Blob $blob = Blob.new(0x22, 0x33);
my Pointer[void] $src-memcpy = nativecast(Pointer[void], $blob);
my Pointer[void] $dest-memcpy = malloc( 32 );
memcpy($src-memcpy,$dest-memcpy,2);
my Pointer[int] $inter = nativecast(Pointer[int], $dest-memcpy);
say $inter; # prints NativeCall::Types::Pointer[int]<0x4499560>

但是,除了创建一个函数来执行此操作之外,我认为没有办法让它们脱离 Pointer[int],因为 nativecast 显然在相反的方向上工作,或者至少不是在强制转换为非本机类型(其名称应该很明显)。你会怎么做?

更新:例如,使用数组会使其更可行。不过

my $inter = nativecast(CArray[int16], $dest);
.say for $inter.list;

这可行,但会产生错误:Don't know how many elements a C array returned from a library

更新 2:在 Christoph's answer(谢谢!)之后,我们可以对此进行更详细的阐述,我们可以将值放回 Buf

sub malloc(size_t $size --> Pointer) is native {*}
sub memcpy(Pointer $dest, Pointer $src, size_t $size --> Pointer) is native {*}

my $blob = Blob.new(0x22, 0x33);
my $src = nativecast(Pointer, $blob);
my $dest = malloc( $blob.bytes );
memcpy($dest, $src, $blob.bytes);
my $inter = nativecast(Pointer[int8], $dest);

my $cursor = $inter;

my Buf $new-blob .= new() ;
for 1..$blob.bytes {
    $new-blob.append: $cursor.deref;
    $cursor++;
}

say $new-blob;

我们需要将指针转换为缓冲区使用的完全相同的类型,然后we use pointer arithmetic 运行它。但是,我们使用$blob.bytes 来知道何时结束循环,它仍然有点hacky。有没有更直接的方法?或者只是一种使用 Bufs/Blob 的方式,以便可以轻松地将它们复制到 Native 领域并返回?

【问题讨论】:

    标签: raku nativecall


    【解决方案1】:

    完整示例:

    use NativeCall;
    
    sub malloc(size_t $size --> Pointer) is native {*}
    sub memcpy(Pointer $dest, Pointer $src, size_t $size --> Pointer) is native {*}
    
    my $blob = Blob.new(0x22, 0x33);
    my $src = nativecast(Pointer, $blob);
    my $dest = malloc(nativesizeof(int16));
    memcpy($dest, $src, nativesizeof(int16));
    my $inter = nativecast(Pointer[int16], $dest);
    say $inter.deref.fmt('%x');
    

    我假设您正在寻找 deref 方法,但您的代码还有一些其他问题:

    • memcpy 的声明中使用int32 而不是size_t
    • memcpy 的参数顺序错误,这意味着您将从未初始化的内存读取的两个字节复制到您所谓的不可变 Blob 中
    • 使用普通的int,您可能应该使用大小合适的整数类型,例如int16

    还要注意在memcpy 的声明中使用纯Pointer,这将允许您传入任何指针类型而无需不断地强制转换。

    【讨论】:

    • 嗯,有点,但是$inter 仍然是一个Pointer[int16],一个本机指针,即使我可以打印它(出于某种原因,以相反的顺序)
    • 另外,那不是$blob.bytes 而不是nativesizeof(int16) 吗?无论如何,非常感谢您的回答。
    • @jjmerelo:倒序是由于little endian整数编码;关于您的第二条评论,我选择了nativesizeof(int16),因为在可能的情况下提供目标参数的大小可以说是“更安全”;请注意,我假设您的目标是创建一个 16 位整数,而不是任意本机 blob
    【解决方案2】:

    使用NativeHelpers::Blob:

    use NativeCall;
    use NativeHelpers::Blob;
    
    sub malloc(size_t $size --> Pointer) is native {*}
    sub memcpy(Pointer $dest, Pointer $src, size_t $size --> Pointer) is native {*}
    
    my $blob = Blob.new(0x22, 0x33);
    my $src = nativecast(Pointer, $blob);
    my $dest = malloc( $blob.bytes );
    memcpy($dest, $src, $blob.bytes);
    my $inter = nativecast(Pointer[int8], $dest);
    
    my Blob $esponja = blob-from-pointer( $inter, :2elems, :type(Blob[int8]));
    say $esponja;
    

    这个程序extends Christoph's answer添加了blob-from-pointer函数,它将返回原始的blob:Blob[int8]:0x&lt;22 33&gt;。这个答案现在也是in the documentation

    【讨论】:

      猜你喜欢
      • 2022-08-15
      • 1970-01-01
      • 1970-01-01
      • 2016-02-16
      • 1970-01-01
      • 2022-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多