如何使用NativeCall处理varargs

Kai*_*epi 11 c perl6 nativecall

我正在为Editline编写绑定,并且其中一个函数history执行了这部分库的大部分工作,但有几个可能的签名:

:(Pointer[Internal], Pointer[Event], int32 --> int32)
:(Pointer[Internal], Pointer[Event], int32, int32 --> int32)
:(Pointer[Internal], Pointer[Event], int32, Str --> int32)
# etc.
Run Code Online (Sandbox Code Playgroud)

第三个参数是一个标志,用于确定history应该使用给定的参数调用哪个函数,但由于这些符号未导出,因此我无法使用它们.我怎样才能找到使用该功能的方法?我不能使用多子或用于cglobal将其转换为a Pointer,然后使用正确的签名.

编辑:我知道is symbol,但我想知道是否有更好的方法可以解决这个问题,因为有9个不同的签名要写

Bra*_*ert 3

\n\n

您可以使用 Raku 函数包装本机函数:

\n\n
sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $flag, $c? --> int32 ){\n  given $flag {\n    when 0|2 {\n      sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(\xe2\x80\xa6) {}\n      history( $a, $b, $flag )\n    }\n    when 1|3 {\n      sub history (Pointer[Internal], Pointer[Event], int32, int32 --> int32) is native(\xe2\x80\xa6) {}\n      history( $a, $b, $flag, $c )\n    }\n    when 4 {\n      sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(\xe2\x80\xa6) {}\n      history( $a, $b, $flag, $c )\n    }\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

或者你可以将每个版本包装在它自己的多重版本中:

\n\n
# Note the flag value ---------------------------------------+\n#                                                            |\n#                                                            V\nmulti sub history ( Pointer[Internal] $a, Pointer[Event] $b, 0 --> int32 ){\n  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(\xe2\x80\xa6) {}\n  history( $a, $b, 0 )\n}\nmulti sub history ( Pointer[Internal] $a, Pointer[Event] $b, 2 --> int32 ){\n  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(\xe2\x80\xa6) {}\n  history( $a, $b, 2 )\n}\n\nmulti sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $flag where 1|3, int32 $c --> int32 ){\n  sub history (Pointer[Internal], Pointer[Event], int32, int32 --> int32) is native(\xe2\x80\xa6) {}\n  history( $a, $b, $flag, $c )\n}\n\nmulti sub history ( Pointer[Internal] $a, Pointer[Event] $b, 4, Str:D $c --> int32 ){\n  sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(\xe2\x80\xa6) {}\n  history( $a, $b, 4, $c )\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

您甚至可以根据参数确定要给出的正确标志。仅当每个签名只有一个标志时,这才有效。
\n(因此下面的示例不遵循上面的 where02具有相同的签名。)

\n\n
multi sub history ( Pointer[Internal] $a, Pointer[Event] $b --> int32 ){\n  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(\xe2\x80\xa6) {}\n  history( $a, $b, 0 )\n}\n\nmulti sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $c --> int32 ){\n  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(\xe2\x80\xa6) {}\n  history( $a, $b, 1, $c )\n}\n\nmulti sub history ( Pointer[Internal] $a, Pointer[Event] $b, Str:D $c --> int32 ){\n  sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(\xe2\x80\xa6) {}\n  history( $a, $b, 4, $c )\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

您可以编写具有不同名称的包装器:

\n\n
sub foo ( Pointer[Internal] $a, Pointer[Event] $b --> int32 ){\n  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(\xe2\x80\xa6) {}\n  history( $a, $b, 0 )\n}\n\nsub bar ( Pointer[Internal] $a, Pointer[Event] $b, int32 $c --> int32 ){\n  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(\xe2\x80\xa6) {}\n  history( $a, $b, 1, $c )\n}\n\nsub baz ( Pointer[Internal] $a, Pointer[Event] $b, Str:D $c --> int32 ){\n  sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(\xe2\x80\xa6) {}\n  history( $a, $b, 4, $c )\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

您可以通过使用 来做到这一点,而无需包装器is symbol

\n\n
sub foo (Pointer[Internal], Pointer[Event], int32        --> int32) is native(\xe2\x80\xa6) is symbol<history> {}\nsub bar (Pointer[Internal], Pointer[Event], int32, int32 --> int32) is native(\xe2\x80\xa6) is symbol<history> {}\nsub baz (Pointer[Internal], Pointer[Event], int32, Str   --> int32) is native(\xe2\x80\xa6) is symbol<history> {}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

您还可以nativecast在包装函数中使用生成的 Signature 对象:

\n\n
sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $flag, $c? --> int32 ){\n  my \\I32 = Parameter.new( type => int32 );\n  my \\PI  = Parameter.new( type => Pointer[Internal] );\n  my \\PE  = Parameter.new( type => Pointer[Event] );\n  my \\STR = Parameter.new( type => Str );\n\n  my @params = ( PI, PE, I32 );\n  given $flag {\n    when 0|2 {\n    }\n    when 1|3 {\n      @params.push( I32 );\n    }\n    when 4 {\n      @params.push( STR );\n    }\n  }\n\n  my \\signature = Signature.new( params => @params.List, returns => int32 );\n\n  # fill this out -----------V\n  my \\history-ptr = cglobal( \xe2\x80\xa6, \'history\', Pointer );\n\n  my &history = nativecast( signature, history-ptr );\n\n  history( $a, $b, $flag, ($c if +@params == 4) );\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这就是您为 C\xe2\x80\x99sprintfscanf.

\n\n
\n\n

无论您使用上面的哪一种,您都需要某种方法来确定需要调用哪种变体。

\n\n

即使在 C 中,也必须有一种方法来根据当前或先前的参数确定参数的数量和类型。

\n\n

参数的数量printf和类型基于第一个参数,即格式。

\n\n

AC 函数可以通过尾随空参数来确定参数的数量。在这种情况下,你必须告诉 Raku。

\n\n

无论底层外部函数如何处理va_args,您都必须将该算法以某种形式复制到 Raku 中。它不能只是猜测。

\n\n

如果您有几个工作原理相似的外部函数,您可以为它们创建一个包装生成器。

\n