Dart FFI 保留 Struct 指针
Dart FFI keep Struct pointer
我正在尝试从 dart 调用 C 库。作为生成器方法的C代码如
a_struc create_struct(void);
然后是接受结构指针的方法,例如:
const char *
get_info(const a_struc * s);
我已经使用 ffigen 创建了 dart 绑定并且我有
class a_struct extends ffi.Struct {
}
a_struct create_struct() {
return create_struct();
}
late final create_structPtr =
_lookup<ffi.NativeFunction<a_struct Function()>>(
'create_struct');
late final create_struct =
create_structPtr
.asFunction<a_struct Function()>();
和
ffi.Pointer<ffi.Int8> get_info(
ffi.Pointer<a_struct> a_struct,
) {
return get_info(
a_struct,
);
}
late final get_infoPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<ffi.Int8> Function(
ffi.Pointer<a_struct>)>>('rcl_publisher_get_topic_name');
late final get_info =
get_infoPtr.asFunction<
ffi.Pointer<ffi.Int8> Function(ffi.Pointer<a_struct>)>();
我的问题是我不知道如何从 create_struct
生成的飞镖 a_struct
中调用方法 get_info
。实际上,get_info
需要一个 ffi.Pointer<a_struct>
但我只生成一个没有指针的 a_struct
。由于 dart 已弃用 .addressOf
,我如何从 create_struct
获得 ffi.Pointer<a_struct>
?
当您 return 从 C 到 Dart 的按值构造结构时,该结构被复制到完全由 Dart 管理的可重定位内存块中。
Dart 不提供公开这些对象的底层地址的 API,因此如果您需要通过引用将该数据传递给 C,则需要将其存储在 non-relocatable 本机内存区域(即堆分配它或使用全局 C 状态)并在 Dart 端跟踪指向它的指针。
如果您不能(或不想)修改 C++ 库,您可以使用 Dart FFI 包调用 malloc<MyStruct>()
然后将结构复制到新分配的 space ref=
setter.
final ffi.Pointer<MyStruct> myStructPtr = malloc<MyStruct>()
..ref = createStructFn();
// ... pass myStructPtr to other FFI functions by reference ...
malloc.free(myStructPtr);
请注意 StructPointer
中的 ref=
setter 登陆 Dart on Jan 12, 2022(最近,在撰写本文时)。
完整示例如下。
C++:
// Build command: g++ -shared lib.cc -o lib.dll -Wl,--out-implib,lib.a
#include <cstdlib>
extern "C" {
typedef struct {
const char* info;
} MyStruct;
MyStruct CreateStruct() {
return {.info = "Hello Dart!"};
}
const char* GetInfo(MyStruct* s) {
return s->info;
}
}
飞镖:
import 'dart:ffi' as ffi;
import 'package:ffi/ffi.dart';
class MyStruct extends ffi.Struct {
external ffi.Pointer<Utf8> info;
}
typedef CreateStruct = MyStruct Function();
typedef GetInfo = ffi.Pointer<Utf8> Function(ffi.Pointer<MyStruct>);
void main() {
// Load FFI procs.
final lib = ffi.DynamicLibrary.open('lib.dll');
final createStructFn =
lib.lookupFunction<CreateStruct, CreateStruct>('CreateStruct');
final getInfoFn = lib.lookupFunction<GetInfo, GetInfo>('GetInfo');
// Allocate a native memory region and copy the returned struct into it.
final myStructPtr = malloc<MyStruct>()..ref = createStructFn();
// It's a pointer, so we can pass by reference.
final result = getInfoFn(myStructPtr);
print(result.toDartString());
// Cleanup!
malloc.free(myStructPtr);
}
顺便说一句:在 "returning structs by value" features 登陆之前,所有 从 C 传递到 Dart 的结构必须通过引用传递。这就是 addressOf
最初在所有 FFI 结构上可用的原因——它们都是 是 ffi.Pointer
。为了支持 Dart-managed 存储后端,ffi.Pointer
需要与 ffi.Struct
分离。
结果是一个更明智的API!例如,您可以有一个 Pointer<Pointer<Uint8>>
,它的功能完全符合您的预期。
我正在尝试从 dart 调用 C 库。作为生成器方法的C代码如
a_struc create_struct(void);
然后是接受结构指针的方法,例如:
const char *
get_info(const a_struc * s);
我已经使用 ffigen 创建了 dart 绑定并且我有
class a_struct extends ffi.Struct {
}
a_struct create_struct() {
return create_struct();
}
late final create_structPtr =
_lookup<ffi.NativeFunction<a_struct Function()>>(
'create_struct');
late final create_struct =
create_structPtr
.asFunction<a_struct Function()>();
和
ffi.Pointer<ffi.Int8> get_info(
ffi.Pointer<a_struct> a_struct,
) {
return get_info(
a_struct,
);
}
late final get_infoPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<ffi.Int8> Function(
ffi.Pointer<a_struct>)>>('rcl_publisher_get_topic_name');
late final get_info =
get_infoPtr.asFunction<
ffi.Pointer<ffi.Int8> Function(ffi.Pointer<a_struct>)>();
我的问题是我不知道如何从 create_struct
生成的飞镖 a_struct
中调用方法 get_info
。实际上,get_info
需要一个 ffi.Pointer<a_struct>
但我只生成一个没有指针的 a_struct
。由于 dart 已弃用 .addressOf
,我如何从 create_struct
获得 ffi.Pointer<a_struct>
?
当您 return 从 C 到 Dart 的按值构造结构时,该结构被复制到完全由 Dart 管理的可重定位内存块中。
Dart 不提供公开这些对象的底层地址的 API,因此如果您需要通过引用将该数据传递给 C,则需要将其存储在 non-relocatable 本机内存区域(即堆分配它或使用全局 C 状态)并在 Dart 端跟踪指向它的指针。
如果您不能(或不想)修改 C++ 库,您可以使用 Dart FFI 包调用 malloc<MyStruct>()
然后将结构复制到新分配的 space ref=
setter.
final ffi.Pointer<MyStruct> myStructPtr = malloc<MyStruct>()
..ref = createStructFn();
// ... pass myStructPtr to other FFI functions by reference ...
malloc.free(myStructPtr);
请注意 StructPointer
中的 ref=
setter 登陆 Dart on Jan 12, 2022(最近,在撰写本文时)。
完整示例如下。
C++:
// Build command: g++ -shared lib.cc -o lib.dll -Wl,--out-implib,lib.a
#include <cstdlib>
extern "C" {
typedef struct {
const char* info;
} MyStruct;
MyStruct CreateStruct() {
return {.info = "Hello Dart!"};
}
const char* GetInfo(MyStruct* s) {
return s->info;
}
}
飞镖:
import 'dart:ffi' as ffi;
import 'package:ffi/ffi.dart';
class MyStruct extends ffi.Struct {
external ffi.Pointer<Utf8> info;
}
typedef CreateStruct = MyStruct Function();
typedef GetInfo = ffi.Pointer<Utf8> Function(ffi.Pointer<MyStruct>);
void main() {
// Load FFI procs.
final lib = ffi.DynamicLibrary.open('lib.dll');
final createStructFn =
lib.lookupFunction<CreateStruct, CreateStruct>('CreateStruct');
final getInfoFn = lib.lookupFunction<GetInfo, GetInfo>('GetInfo');
// Allocate a native memory region and copy the returned struct into it.
final myStructPtr = malloc<MyStruct>()..ref = createStructFn();
// It's a pointer, so we can pass by reference.
final result = getInfoFn(myStructPtr);
print(result.toDartString());
// Cleanup!
malloc.free(myStructPtr);
}
顺便说一句:在 "returning structs by value" features 登陆之前,所有 从 C 传递到 Dart 的结构必须通过引用传递。这就是 addressOf
最初在所有 FFI 结构上可用的原因——它们都是 是 ffi.Pointer
。为了支持 Dart-managed 存储后端,ffi.Pointer
需要与 ffi.Struct
分离。
结果是一个更明智的API!例如,您可以有一个 Pointer<Pointer<Uint8>>
,它的功能完全符合您的预期。