首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Dart FFI保持结构指针

Dart FFI保持结构指针
EN

Stack Overflow用户
提问于 2022-01-01 12:01:42
回答 1查看 1.2K关注 0票数 4

我正在用飞镖打电话给C库。作为生成器方法的C代码,如

代码语言:javascript
复制
a_struc  create_struct(void);

然后,接受指向struct的指针的方法,如:

代码语言:javascript
复制
const char *
 get_info(const a_struc * s);

我使用ffigen创建了省道绑定,并且我已经

代码语言:javascript
复制
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()>();

代码语言:javascript
复制
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>)>();

我的问题是,我不知道如何从由get_info生成的dart a_struct调用方法create_struct。实际上,get_info需要一个ffi.Pointer<a_struct>,但是我只生成一个没有指针的a_struct。既然dart不推荐.addressOf,我如何从create_struct获得一个ffi.Pointer<a_struct>

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-25 12:33:11

当您将结构值从C返回给Dart时,结构将被复制到由Dart完全管理的可重定位内存块中。

Dart不提供公开这些对象的底层地址的API,因此如果需要通过引用将数据传递给C,则需要将其存储在不可重定位的本机内存区域(即堆分配它或使用全局C状态),并在data端跟踪指向它的指针。

如果不能(或者不愿意)修改C++库,可以使用Dart包调用malloc<MyStruct>(),然后使用ref= setter将结构复制到新分配的空间中。

代码语言:javascript
复制
final ffi.Pointer<MyStruct> myStructPtr = malloc<MyStruct>()
  ..ref = createStructFn();

// ... pass myStructPtr to other FFI functions by reference ...

malloc.free(myStructPtr);

请注意,ref=StructPointer中的设置器落在了Dart 2022年1月12日 (最近,在编写本文时)。

下面是完整的例子。

C++:

代码语言:javascript
复制
// 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;
  }
}

Dart:

代码语言:javascript
复制
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);
}

顺便提一句:在“按值返回结构”特征登陆之前,所有从C传递到Dart的结构都必须通过引用传递。这就是为什么addressOf最初在所有FFI结构上可用的原因--它们都是ffi.Pointer的。为了支持Dart管理的存储后端,ffi.Pointer需要与ffi.Struct分离。结果是一个更加合理的API!例如,您可以拥有一个Pointer<Pointer<Uint8>>,它的功能与您预期的完全相同。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70548745

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档