Skip to content

How handle pointer to structs as array ? #341

Closed

Description

@kascote

Hi, I'm working with an struct like this

struct ncmenu_section {
  const char* name; 
  int itemcount;
  struct ncmenu_item* items;
}

and ffigen is generating

class ncmenu_section extends ffi.Struct {
  external ffi.Pointer<ffi.Int8> name;
  @ffi.Int32()
  external int itemcount;
  external ffi.Pointer<ncmenu_item> items;
}

The question I have is how to handle ncmenu_section.items as an array.
All the examples I saw use Pointer<Pointer<ncmenu_item>> to handle arrays, but I can't make it work. I tried to casting Pointer<Pointer<ncmenu_item> to Pointer<ncmenu_item> and other crazy stuff but nothing works.

For example I was trying this

ffi.Pointer<ffi.Pointer<ncmenu_item>> pItems = allocator<ffi.Pointer<ncmenu_item>>(2);
pItems[0] = mi1;
pItems[1] = mi2;

ffi.Pointer<ncmenu_section> sec = allocator<ncmenu_section>(1);
sec.ref
  ..name = "Section Menu".toNativeUtf8().cast() // I know this is leaking, just for the example
  ..items = pItems.cast<ncmenu_item>()
  ..itemcount = 2;

All this assignments works, but when call to the API with the final structure, give me errors or breaks.
If I only use 1 element in all the cases (items and section) and not use Pointer<Pointer<>> all works ok.

TIA

Activity

  1. dcharkes commented on Jan 22, 2022

    @dcharkes
    Collaborator

    Do you want an array of struct values or an array of struct pointers?

    If you want an array of struct values, you should not use Pointer<Pointer<ncmenu_item>> just Pointer<ncmenu_item>. (Pointers already provide array access.)

    class ncmenu_item extends ffi.Struct {
      external ffi.Pointer<ffi.Int8> description;
      // ignored next  field.
    }
    
    class ncmenu_section extends ffi.Struct {
      external ffi.Pointer<ffi.Int8> name;
      @ffi.Int32()
      external int itemcount;
      external ffi.Pointer<ncmenu_item> items;
    }
    
    void main() {
      using((Arena allocator) {
        final pItems = allocator<ncmenu_item>(2);
        pItems[0]..description = "Foo".toNativeUtf8(allocator: allocator).cast();
        pItems[1]..description = "Bar".toNativeUtf8(allocator: allocator).cast();
    
        final sec = allocator<ncmenu_section>(1);
        sec.ref
          ..name = "Section Menu".toNativeUtf8(allocator: allocator).cast()
          ..items = pItems.cast<ncmenu_item>()
          ..itemcount = 2;
    
        // Use allocated things.
    
        // All allocations in Arena are freed at the end of this scope.
      });
    }

    P.S. you can use the Arena allocator with using(...) to automatically free memory at the end of the scope.

    If you want an array of struct pointers, your C type should be:

    struct ncmenu_section {
      const char* name; 
      int itemcount;
      struct ncmenu_item** items; // note the `**`.
    }

    (But based on https://notcurses.com/html/structncmenu__section.html I'm guessing you're not looking for that.)

  2. kascote commented on Jan 22, 2022

    @kascote
    Author

    worked nice!! thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions