Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

275
Views
Dart FFI keep Struct pointer

I am trying to call a C library from dart. The C code as a genertor method such as

a_struc  create_struct(void);

and then methods that take in a pointer to struct, such as:

const char *
 get_info(const a_struc * s);

I have created the dart binding using ffigen and I have

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()>();

and

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>)>();

My problem is that I don't know how to call the method get_info from the dart a_struct generated by create_struct. Indeed, get_info expects a ffi.Pointer<a_struct> but I only generate a a_struct without the pointer. Since dart deprecated .addressOf, how can I obtain a ffi.Pointer<a_struct> from create_struct?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

When you return a struct by value from C to Dart, the struct is copied into a relocatable memory block that's fully managed by Dart.

Dart doesn't provide an API that exposes the underlying address of these objects, and so if you need to pass that data to C by reference, you'll need to store it in a non-relocatable native memory region (i.e. heap allocate it or use global C state) and keep track of a pointer to it on the Dart side.

If you can't (or would prefer not to) modify the C++ library, you could use the Dart FFI package to call malloc<MyStruct>() and then copy the struct into the newly allocated space with ref= setter.

final ffi.Pointer<MyStruct> myStructPtr = malloc<MyStruct>()
  ..ref = createStructFn();

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

malloc.free(myStructPtr);

Note that the ref= setter in StructPointer landed in Dart on Jan 12, 2022 (quite recently, at the time of writing).

Full example below.

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;
  }
}

Dart:

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);
}

As an aside: Before the "returning structs by value" features landed, all structs passed from C to Dart had to be passed by reference. That's the reason addressOf was initially available on all FFI structs -- they all were ffi.Pointers. To support Dart-managed storage backends, ffi.Pointer needed to be decoupled from ffi.Struct. The result is a much more sensible API! For example, you can have a Pointer<Pointer<Uint8>> and it functions exactly as you'd expect.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!