如何向回调函数传递用户数据?NativeCall接口调用报错问题
exif_content_foreach_entry的回调类型问题 看起来你在Perl 6的NativeCall绑定libexif的exif_content_foreach_entry时遇到了类型不匹配的问题——这很常见,毕竟C的void*和Perl 6的类型系统需要仔细对齐。让我们一步步解决这个问题:
首先先明确C函数的核心定义,这是我们对齐类型的基准:
typedef void (* ExifContentForeachEntryFunc) (ExifEntry *, void *user_data);
void exif_content_foreach_entry (ExifContent *content, ExifContentForeachEntryFunc func, void *user_data);
你的初步实现里有两个关键的类型匹配错误:
1. Buf 类型无法对应C的 void*
C的void*是通用内存指针,而Perl 6的Buf是字节缓冲区对象,NativeCall无法直接将Buf转换为void*指针类型,这是报错的核心原因。我们需要用Pointer(或OpaquePointer,如果不需要主动解引用)来对应C的void*。
2. 回调函数签名必须严格对齐C的定义
回调的第二个参数类型必须和C的void*完全一致,也就是Pointer,而不是Buf。
修正后的绑定代码
首先确保你已经正确定义了C指针对应的Perl 6类:
class ExifEntry is repr('CPointer') is native(LIB) { } class ExifContent is repr('CPointer') is native(LIB) { }
然后修正exif_content_foreach_entry的绑定:
sub exif_content_foreach_entry( ExifContent $exifcontent, &func (ExifEntry $entry, Pointer $user_data), Pointer $user_data ) is native(LIB) is export { * }
如果想让回调类型更清晰,也可以先定义回调子类型再绑定:
sub ExifContentForeachEntryFunc(ExifEntry $entry, Pointer $user_data) is native(LIB) { * } sub exif_content_foreach_entry( ExifContent $content, &func where * ~~ ExifContentForeachEntryFunc, Pointer $user_data ) is native(LIB) is export { * }
传递Perl 6数据作为user_data
如果需要把Perl 6的对象/自定义数据传递到回调里,可以用NativeCall的data_pointer和deref函数来处理指针与Perl 6数据的转换:
use NativeCall; # 准备要传递的Perl 6业务数据 my $app_data = { processed_tags => 0, tag_details => [] }; # 获取指向该数据的C兼容指针 my $data_ptr = data_pointer($app_data); # 调用函数,在回调中取回并操作数据 exif_content_foreach_entry($my_content, -> ExifEntry $entry, Pointer $ptr { my $data = deref($ptr); $data<processed_tags>++; # 这里可以继续处理ExifEntry的内容,比如提取标签信息存入$data<tag_details> }, $data_ptr);
这样调整后,类型就能完全匹配C函数的要求,应该可以解决你遇到的报错问题了。
内容的提问来源于stack exchange,提问作者Fernando Santagata

