Let’s create a c file named
random_number.c
For generating random number in c, we use
rand
. Here is the snippet
int fetch_number()
int c, n;
srand(time(0));
n = rand() % 100 + 1;
return n;
Note: We are capping the values from 0 to 100
We will create a header file randomnumber.h, and paste the declaration of our function inside it.
// randomnumber.h
int fetch_number();
Inside our random_number.c, we will import this header file and implement the definition of fetch_number . Our final file looks like this
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "randomnumber.h"
int main()
return 0;
// Definition omitted for brevity. Basically, it's the above function only :)
Let’s test our c function, navigate to the folder containing the program and run
gcc random_number.c -o random_number
This generates our output file as random_number.o Run this output file by
./random_number
Output from C library
Next, we will create our dynamic library (librandomnumber.so)
To create a dynamic library, write the following command:
gcc -shared -o librandomnumber.so random_number.o
// librandomnumber.o is the name of your dynamic library
// random_number.o is the object file created from the above step
Note: The library name can be anything, but should start with “lib” and end with .so
The compiler will later identify a library by searching for files beginning with “lib” and ending with the naming convention,.so
Dynamic Library in Linux
Call from Flutter on Linux
Drag and drop the library (librandomnumber.so) in our flutter project. We create a library subfolder and drop it there.
Libraries inside Flutter projectSteps to call a function from C
We will call our dynamic libraries from Flutter Desktop now using Dart FFI in Linux
Import the dart ffi package(present inside Flutter) as
import 'dart:ffi'
This has a class DynamicLibrary. We call the method open and load our dynamic library (librandomnumber.so).
final dyLib = DynamicLibrary.open( 'lib/library/linux/librandomnumber.so', );
Lookup for the symbol from the loaded dynamic library using lookup or lookupFunction.
dyLib.lookup<NativeFunction<fetch_number_func>>(
'fetch_number',
// This returns a pointer
Note: The lookup takes in a native function (which represents a function in C)
Our fetch_number_func is basically
typedef fetch_number_func = Int32 Function();
and this Int32 comes from dart:ffi, which represents a native signed 32 bit integer in C.
The pointer returned from the above step is converted into Dart function
final number = fetchNumberPointer.asFunction<FetchNumber>();
number(); // Call the function
where FetchNumber is our function
typedef FetchNumber = int Function();
Passing parameter from Dart to C
Let’s create a c file named string_ops.c We will define a function, which takes in a string parameter, reverses it, and sends it back. Here is the snippet
void reverse(char *str) {
// Calculate length of string.
int l = 0;
while (*(str + l) != '\0')
// Initialize.
int i;
char *first, *last, temp;
first = str;
last = str;
for (i = 0; i < l - 1; i++) {
last++;
// Iterate from both ends, swapping first and last as we go.
for (i = 0; i < l / 2; i++) {
temp = *last;
*last = *first;
*first = temp;
first++;
last--;
As seen in the above section, we will create a header file stringops.h and paste the declaration of our function inside it.
// stringops.h
void reverse(char *str);
Inside our string_ops.c, we will import this header file and implement the definition of reverse . Our final file looks like this
#include<stdio.h>
#include "stringops.h"
int main()
return 0;
// Definition omitted for brevity. Basically, it's the above function only :)
Finally, we create our header file, libstringops.so (see the steps above)
Call from Flutter
We copy-paste this header file inside our flutter project
Libraries inside Flutter project
Open the dynamic library using the dart ffi
final dylib = DynamicLibrary.open(
'lib/library/linux/libstringops.so',
Now we need to pass in the parameter, and this should be something that C understands. In short, we need to convert our Flutter Strings to Pointer.
In the header file stringops.h, let’s add in our struct
struct Name
char *firstname;
char *lastname;
struct Name create_name(char *firstname, char *lastname);
Inside our string_ops.c, we have already imported this header file. Let’s implement the definition of create_name . Our final file looks like this
#include<stdio.h>
#include "stringops.h"
int main()
return 0;
struct Name create_name(char *firstname, char *lastname) {
struct Name name;
name.firstname = firstname;
name.lastname = lastname;
return name;
Finally, we create our header file, libstringops.so (see the steps above)
Call from Flutter
Note: We require Dart 2.12 and onwards to call structs from ffi
We copy-paste this header file inside our flutter project
Libraries inside Flutter project
We already have our dynamic library opened (see the above section), now we need to look up our create_name function.
final createName =
dylib.lookupFunction<CreateNameNative, CreateName>('create_name');
As we know now, the lookup function takes in a C function and a Dart function. Our functions look like
// For structs
typedef CreateNameNative = Name Function(
Pointer<Utf8> firstName, Pointer<Utf8> lastName);
typedef CreateName = Name Function(
Pointer<Utf8> firstName, Pointer<Utf8> lastName);
since, we need to pass in the two parameters
Now, here is something new, we have Name
class Name extends Struct {
external Pointer<Utf8> firstName;
external Pointer<Utf8> lastName;
Dart introduces Struct, the supertype of all FFI struct types.
FFI struct types should extend this class and declare fields corresponding to the underlying native structure.
All field declarations in a Struct subclass declaration must be marked external
Rest is the same, we pass in our inputs as toNativeUtf8
String first = 'Aseem';
String second = 'Wangoo';
final fNameUtf8 = first.toNativeUtf8();
final lNameUtf8 = second.toNativeUtf8();
final name = createName(fNameUtf8, lNameUtf8);
// createName is from the above
Finally, we have our response in the variable name The response(which is of type UTF-8) is converted toDartString
final fname = name.firstName.toDartString();
final lname = name.lastName.toDartString();