How to handle ruby ​​arrays in ruby ​​ffi gem?

I want to use ruby ​​ffi gem to call a function c that has an array as an input variable and the output is an array. That is, the c function looks like this:

double *my_function(double array[], int size) 

I created a ruby ​​binding as:

 module MyModule extend FFI::Library ffi_lib 'c' ffi_lib 'my_c_lib' attach_function :my_function, [:pointer, int], :pointer 

I would like to call the ruby ​​code, for example:

 result_array = MyModule.my_function([4, 6, 4], 3) 

How can I do it?

+5
c ruby ffi
source share
1 answer

Say this is the library you want to use in a 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 this:

 $ 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 is ready for use 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 internal memory with automatic garbage collection as a sweetener. When MemoryPointer goes out of scope, memory is freed as part of the garbage collection process.

Therefore, you do not need to directly call pointer.free . Also, just to check if you need to manually free result_pointer , I called result_pointer.free after printing the array extraction and got this warning

 warning: calling free on non allocated pointer #<FFI::Pointer address=0x007fd32b611ec0> 

So it seems you do not need to manually release result_pointer .

+4
source share

All Articles