【问题标题】:How to correctly use CPointer and CStruct in NativeCall interface如何在 NativeCall 接口中正确使用 CPointer 和 CStruct
【发布时间】:2018-04-24 09:07:25
【问题描述】:

我正在尝试让这个NativeCall 运行的示例:

use NativeCall;

class p_timespec is repr('CPointer') {
    has uint32 $.tv_sec;
    has long $.tv_nanosecs;
}

sub clock_gettime(uint32 $clock-id, p_timespec $tspec --> uint32) is native(Str) { * };

my p_timespec $this-time;

my $result = clock_gettime( 0, $this-time);

say "$result, $this-time";

它只是段错误,当您使用指针时会发生这种情况,而您不应该这样做。在这种情况下,可能是由于p_timespec的声明;我实际上已将其声明为CPointer,尽管the struct should be OK。但是,从分段错误中,我无法理解真正的问题所在。有人可以帮忙吗?

【问题讨论】:

  • 可能(几乎)不可能做出更多的宽容,仅仅是因为 C 端不进行任何验证。最后,您必须使用常用的 C 调试工具(如 gdb、valgrind)来帮助您。
  • repr 不应该是 CStruct insetad 的 CPointer 吗? CPointer 上的属性没有意义,可能应该引发编译器错误...
  • 您的系统是否有正确的p_timespec.tv_sec 类型?在我的系统上应该是int64,而不是uint32
  • @Kaiepi 从这个意义上说,它似乎更宽容一些。显然,问题在于声明一个具有结构的 CPointer。
  • @jjmerelo:您是否正在使用 Perl 6 版本的 Time::HiRes

标签: posix raku nativecall


【解决方案1】:

这里有两个问题。

  1. 应使用CStruct 表示
  2. 您需要创建一个结构实例以填充数据,否则您将传递一个空指针

这似乎有效:

use NativeCall;

class p_timespec is repr('CStruct') {
    has uint32 $.tv_sec;
    has long $.tv_nanosecs;
}

sub clock_gettime(uint32 $clock-id, p_timespec $tspec --> uint32) is native(Str) { * };

my p_timespec $this-time .= new;

my $result = clock_gettime( 0, $this-time);

say "$result, $this-time.tv_sec(), $this-time.tv_nanosecs()";

至于调试,Rakudo的安装过程还安装了一个perl6-gdb-m和一个perl6-valgrind-m;后者虽然速度较慢,但​​往往会提供一些有关内存错误的有用信息。

【讨论】:

  • 出于好奇,为什么几乎没有人使用repr<CStruct> 语法?
  • 其实clock_gettime使用一个指针作为第二个参数。这是否意味着您可以使用 CStruct 而不是 CPointers?你什么时候真正需要使用 CPointers?
  • CStruct 实例已经作为指向内存的指针传递,因此不需要额外的指针级别。 CPointer 在您只想将数据结构作为不透明指针处理时很有用,而不关心其中的内容。例如,当有一个 C 库分配/释放结构并提供对其进行操作的函数时,这很有效,而且您永远不应该直接插入它。
  • @JonathanWorthington "CPointer ... 处理 ... 作为一个不透明的指针 ... 你永远不应该直接戳它。"你会说Christoph's comment 是正确的,或者至少将has 和/或HASrepr('CPointer') 一起使用会引起警告?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-22
  • 2020-07-13
  • 2018-08-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-09
相关资源
最近更新 更多