5

I am learning Dart now and I playing with Dart's Interoperability with C. I am able to use a C method with two int params. Code below:

hello.dart

import 'dart:ffi' as ffi;

typedef sum_func = ffi.Int32 Function(ffi.Int32 a, ffi.Int32 b);
typedef Sum = int Function(int a, int b);
...
final dylib = ffi.DynamicLibrary.open(path);
final sumPointer = dylib.lookup<ffi.NativeFunction<sum_func>>('sum');

final sum = sumPointer.asFunction<Sum>();
print('3 + 5 = ${sum(3, 5)}');

hello.c

int sum(int a, int b){
    return a + b;
}

hello.h

int add(int x, int y)

hello.def

LIBRARY   hello
EXPORTS
   sum

This all works really well, but I also want to have an max C method, which takes an int array as an input and returns the biggest number. How can I do this? I've implemented all the required code in C, but I am not sure how do I "link" it with Dart. Could anyone help me please?

Dan Cantir
  • 2,915
  • 14
  • 24

1 Answers1

5

First, I really want to say that I am not a C programmer and especially when it comes to pointers I am not even pretending I have a fully understanding of how to do this kind of things the most optimal way.

With this out of the way here is my solution based on the primitives example found here: https://github.com/dart-lang/samples/tree/master/ffi/primitives

primitives.dart

import 'dart:ffi';
import 'dart:io' show Platform;

import 'package:ffi/ffi.dart';

typedef max_func = Int32 Function(Pointer<Int32> list, Int32 size);
typedef Max = int Function(Pointer<Int32> list, int size);

void main() {
  var path = './primitives_library/libprimitives.so';
  if (Platform.isMacOS) path = './primitives_library/libprimtives.dylib';
  if (Platform.isWindows) path = r'primitives_library\Debug\primitives.dll';
  final dylib = DynamicLibrary.open(path);

  final list = [1, 5, 3, 59030, 131000, 0];
  final listPtr = intListToArray(list);

  final maxPointer = dylib.lookup<NativeFunction<max_func>>('max');
  final max = maxPointer.asFunction<Max>();
  print('${max(listPtr, list.length)}'); // 131000
  malloc.free(listPtr);
}

Pointer<Int32> intListToArray(List<int> list) {
  final ptr = malloc.allocate<Int32>(sizeOf<Int32>() * list.length);
  for (var i = 0; i < list.length; i++) {
    ptr.elementAt(i).value = list[i];
  }
  return ptr;
}

primitives.h

int max(int *listPtr, int size);

primitives.c

#include "primitives.h"

int max(int *listPtr, int size)
{
  int currentMax = *listPtr;

  for (int i = 0; i < size; i++)
  {
    if (currentMax < *listPtr)
    {
      currentMax = *listPtr;
    }
    listPtr++;
  }

  return currentMax;
}
julemand101
  • 28,470
  • 5
  • 52
  • 48
  • How do we do the same with an array of strings? I am unable to figure out how to pass string array to c from Dart – Ganesh Rathinavel Sep 13 '20 at 19:01
  • 1
    I will suggest you create a new question since it does not really have much to do with the current question. – julemand101 Sep 13 '20 at 21:24
  • This answer seems to be invalid now because of the removal of `allocate` in the new versions of dart:ffi (https://pub.dev/packages/ffi/changelog#030-nullsafety0). Since documentation seems to be bad, could anyone give correct replacement for `allocate(count: list.length)`? – Siddhant Mar 05 '21 at 11:32
  • @Siddhant Thanks for noting. I have updated the Dart code so it is compatible with the ffi package version 1.0.0. Can you try and see if it works? – julemand101 Mar 05 '21 at 12:26
  • @julemand101 I think it should be `malloc.allocate(sizeOf()*list.length);` as it requires byte count according to https://github.com/dart-lang/ffi/blob/24eb0a066d3b32e54682a57e4780af4e2efbd2d3/lib/src/allocation.dart#L56 . – Siddhant Mar 05 '21 at 15:11
  • @Siddhant Seems like you are indeed correct about that. What a mess... but I have updated my answer. :D – julemand101 Mar 05 '21 at 17:52