I want to use the ruby ffi gem to call a c function which has an array as an input variable and the output is an array. That is, the c function looks like:
double *my_function(double array[], int size)
I have created the ruby binding as:
module MyModule
extend FFI::Library
ffi_lib 'c'
ffi_lib 'my_c_lib'
attach_function :my_function, [:pointer, int], :pointer
I will like to make a call in ruby code like:
result_array = MyModule.my_function([4, 6, 4], 3)
How do I go about this?
Let's say that this is the library you wish to use in your ruby script, call it my_c_lib.c
:
#include <stdlib.h>
double *my_function(double array[], int size)
{
int i = 0;
double *new_array = malloc(sizeof(double) * size);
for (i = 0; i < size; i++) {
new_array[i] = array[i] * 2;
}
return new_array;
}
You can compile it like so:
$ gcc -Wall -c my_c_lib.c -o my_c_lib.o
$ gcc -shared -o my_c_lib.so my_c_lib.o
Now, it's ready to use in in your ruby code (my_c_lib.rb
):
require 'ffi'
module MyModule
extend FFI::Library
# Assuming the library files are in the same directory as this script
ffi_lib "./my_c_lib.so"
attach_function :my_function, [:pointer, :int], :pointer
end
array = [4, 6, 4]
size = array.size
offset = 0
# Create the pointer to the array
pointer = FFI::MemoryPointer.new :double, size
# Fill the memory location with your data
pointer.put_array_of_double offset, array
# Call the function ... it returns an FFI::Pointer
result_pointer = MyModule.my_function(pointer, size)
# Get the array and put it in `result_array` for use
result_array = result_pointer.read_array_of_double(size)
# Print it out!
p result_array
And here is the result of running the script:
$ ruby my_c_lib.rb
[8.0, 12.0, 8.0]
A note on memory management...from the docs https://github.com/ffi/ffi/wiki/Pointers:
The FFI::MemoryPointer class allocates native memory with automatic garbage collection as a sweetener. When a MemoryPointer goes out of scope, the memory is freed up as part of the garbage collection process.
So you shouldn't have to call pointer.free
directly. Also, just to check whether you had to manually free result_pointer
, I called result_pointer.free
after printing extracting the array and got this warning
warning: calling free on non allocated pointer #<FFI::Pointer address=0x007fd32b611ec0>
So it looks like you don't have to manually free result_pointer
either.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With