失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 03 Flutter FFI 函数

03 Flutter FFI 函数

时间:2018-11-23 05:08:20

相关推荐

03 Flutter FFI 函数

Flutter FFI 学习笔记系列

《Flutter FFI 最简示例》《Flutter FFI 基础数据类型》《Flutter FFI 函数》《Flutter FFI 字符串》《Flutter FFI 结构体》《Flutter FFI 类》《Flutter FFI 数组》《Flutter FFI 内存管理》《Flutter FFI Dart Native API》

在前面的章节中,演示了如何在 Dart 中访问 C 中的函数。接下来将详细介绍 C 和 Dart 函数的相互调用。

1、Dart 调用 C 函数

1.1 C函数的定义

Dart 语言只能调用 C 语言风格的函数,不能调用 C++ 语言风格的函数,因此,函数需要加上extern "C"前缀,这表示告诉编译器按C语言风格编译该函数。同时,为了避免编译器在编译优化阶段把没有使用到的符号删除掉,需要在函数前面加上__attribute__((visibility("default")))__attribute__((used))

C 语言函数的定义格式如下:

#include <stdint.h>extern "C" __attribute__((visibility("default"))) __attribute__((used))int32_t native_add(int32_t x, int32_t y) {return x + y;}

为了编写方便,可以使用宏定义来简化代码:

#include <stdint.h>#define DART_API extern "C" __attribute__((visibility("default"))) __attribute__((used))DART_API int32_t native_add(int32_t x, int32_t y) {return x + y;}

1.2 Dart函数类型定义

在 Dart 中,需要定义与 C 函数相对应的函数类型,以便在 Dart 中调用。

这里需要使用 Dart Function 定义两个函数类型,一个用于表示 C ,一个用于 Dart,如下:

///对应C语言函数声明:int32_t native_add(int32_t x, int32_t y)typedef Native_add = Int32 Function(Int32 x, Int32 y);///Dart使用的函数typedef FFI_add = int Function(int x, int y);

说明:

上面的Native_add函数类型,是 C 函数在 Dart 中的表示形式,函数的参数和返回值都属性NativeType(例如:Int32);上面的FFI_add函数类型,是 Dart 风格的函数,供 Dart 调用,函数参数和返回值都是 Dart 中的数据类型;当使用 FFI 绑定这两个函数类型的时候,数据类型的转换将由 FFI 内部完成。

1.3 Dart调用C函数

完成函数的声明和定义之后,就可以通过以下步骤在 Dart 中调用 C 函数了:

Android 平台使用DynamicLibrary.open()加载符号信息,iOS 平台使用DynamicLibrary.process()加载符号信息;通过DynamicLibrary.lookup()或者DynamicLibrary.lookupFunction()来查找函数符号,并转为 Dart 函数;

调用 Dart 函数。示例代码如下:

//加载符号DynamicLibrary nativeApi = Platform.isAndroid? DynamicLibrary.open("libnative_ffi.so"): DynamicLibrary.process();//方法1 - 查找函数符号,并转为Dart函数final addFunc1 = nativeApi.lookupFunction<Native_add, FFI_add>("native_add");//方法2 - 查找函数符号,并转为Dart函数FFI_add addFunc2 = nativeApi.lookup<NativeFunction<Native_add>>("native_add").asFunction();//此时,调用Dart函数就是调用C函数int result = addFunc1(1, addFunc2(1, 2));print("1+(1+2)=$result");//输出信息://1+(1+2)=4

说明:

lookupFunction()其实就是lookup()asFunction()的封装,简化代码。

1.4 变长参数函数

C 语言中具有变长参数函数,但是在 FFI 中,必须要指定参数类型和个数才行。

下面这个示例演示了如何在 Dart 调用 C 的变长参数函数:

首先,在 C 中定义一个函数:

#include <stdint.h>#include <stdarg.h>#define DART_API extern "C" __attribute__((visibility("default"))) __attribute__((used))DART_API int multi_sum(int nr_count, ...) {va_list nums;va_start(nums, nr_count);int sum = 0;for (int i = 0; i < nr_count; i++){sum += va_arg(nums, int);}va_end(nums);return sum;}

然后,在 Dart 中定义两个函数类型,与 C 中的函数进行映射:

///对应C语言函数typedef Native_multi_sum = Int32 Function(Int32 numCount, Int32 a, Int32 b, Int32 c);///供Dart所使用的函数typedef FFI_multi_sum = int Function(int numCount, int a, int b, int c);

最后,通过lookupFunction()找到该符号并调用:

final sumFunc = nativeApi.lookupFunction<Native_multi_sum,FFI_multi_sum>("multi_sum");print("result:${sumFunc(3, 1, 2, 3)}");//输出结果//result:6

说明:

2、C 调用 Dart 函数

上面介绍了如何在 Dart 中调用 C 的函数,下面看看如何在 C 中调用 Dart 的函数。

在 Dart 中,只有全局函数才能给被 C 调用。我们可以通过Pointer.fromFunction()函数将 Dart Function 转为 C 的函数指针。fromFunction()函数声明如下:

/// Convert Dart function to a C function pointer, automatically marshalling/// the arguments and return value////// If an exception is thrown while calling `f()`, the native function will/// return `exceptionalReturn`, which must be assignable to return type of `f`.////// The returned function address can only be invoked on the mutator (main)/// thread of the current isolate. It will abort the process if invoked on any/// other thread.////// The pointer returned will remain alive for the duration of the current/// isolate's lifetime. After the isolate it was created in is terminated,/// invoking it from native code will cause undefined behavior.////// Does not accept dynamic invocations -- where the type of the receiver is/// [dynamic].external static Pointer<NativeFunction<T>> fromFunction<T extends Function>(@DartRepresentationOf("T") Function f,[Object? exceptionalReturn]);

下面通过一个示例来演示 C 如何调用 Dart 函数。

首先,在 C 定义一个函数:

#include <malloc.h>#define DART_API extern "C" __attribute__((visibility("default"))) __attribute__((used))DART_APIvoid calc(int32_t src, void (*callback)(int32_t, int32_t)) {int result = src * 10000;callback(src, result);}

然后在 Dart 定义相应的函数类型以及 全局回调函数:

typedef Callback = Void Function(Int32, Int32);typedef Native_calc = Void Function(Int32, Pointer<NativeFunction<Callback>>);typedef FFI_calc = void Function(int, Pointer<NativeFunction<Callback>>);void globalCallback(int src, int result) {print("globalCallback src=$src, result=$result");}

说明:

函数指针的类型为:Pointer<NativeFunction<...>globalCallback()是一个全局函数,用于给 C 调用。

最后,在 Dart 调用 C 的函数:

//加载 C 符号DynamicLibrary nativeApi = Platform.isAndroid? DynamicLibrary.open("libnative_ffi.so"): DynamicLibrary.process();//查找函数FFI_calc calcFunc = nativeApi.lookupFunction<Native_calc, FFI_calc>("calc");//调用函数calcFunc(32, Pointer.fromFunction(globalCallback));//输出结果://I/flutter ( 3920): globalCallback src=32, result=320000

说明:

我们在 Dart 中调用了 C 的calc()函数,并将globalCallback转为函数指针作为calc()的参数;在 C 的calc()函数内,直接把 Dart 的globalCallback当作函数指针进行调用;

最后globalCallback被调用,打印了相应的信息。

3、总结

上面介绍如何通过 FFI 实现 C 与 Dart 的相互调用,在后面的章节中,将会介绍字符串、结构体、数组、内存管理等知识,欢迎关注。

如果觉得《03 Flutter FFI 函数》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。