2015-04-01 24 views
5

Voglio usare il ruby ​​ffi gem per chiamare una funzione c che ha una matrice come variabile di input e l'output è una matrice. Cioè, la funzione c assomiglia:Come gestisco gli array di ruby ​​in ruby ​​ffi gem?

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

ho creato il rubino vincolante:

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

mi piacerebbe fare una chiamata in codice Ruby come:

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

Come faccio a fare questo?

risposta

4

Diciamo che questa è la libreria che si desidera utilizzare nello script rubino, lo chiamano 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; 
} 

È possibile compilare in questo modo:

$ gcc -Wall -c my_c_lib.c -o my_c_lib.o 
$ gcc -shared -o my_c_lib.so my_c_lib.o 

Ora, è pronto a utilizzare nel nel codice ruby ​​(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 

Ed ecco il risultato dell'esecuzione dello script:

$ ruby my_c_lib.rb 
[8.0, 12.0, 8.0] 

Una nota sulla gestione della memoria ... dalla documentazione https://github.com/ffi/ffi/wiki/Pointers:

La FFI :: classe MemoryPointer alloca la memoria nativa con garbage collection automatica come dolcificante. Quando un MemoryPointer esce dal campo di applicazione, la memoria viene liberata come parte del processo di garbage collection.

Quindi non si dovrebbe chiamare direttamente pointer.free. Inoltre, proprio per verificare se si doveva liberi manualmente result_pointer, ho chiamato result_pointer.free dopo la stampa l'estrazione della matrice e ottenuto questo avvertimento

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

così sembra che non si dispone alla libera manualmente result_pointer neanche.