FFI Abkürzung für Foreign Function Interface (Fremdfunktionsschnittstelle). Hierbei handelt es sich um eine Funktion zur Verwendung von Funktionen, die in einer anderen Programmiersprache geschrieben sind. In Ruby bieten das Juwel ffi und die in Ruby gepackte Standardbibliothek Fiddle gleichwertige Funktionen.
Dieses Mal möchte ich das C-Programm von Ruby mit dem bereitgestellten ffi verwenden, was ein Juwel ist.
Gewöhnen wir uns zuerst an ffi. Der aufrufende Code ist unten.
lib.c
int add(int a, int b) {
return a + b;
}
Ich habe ein "add" definiert, das zwei Argumente vom Typ int verwendet und das Ergebnis ihrer Addition zurückgibt.
Um dieses Add von Ruby aus aufzurufen, muss es in das Format der gemeinsam genutzten Bibliothek (* .so) konvertiert werden. Verwenden Sie zum Konvertieren den folgenden Befehl.
$ gcc -shared lib.c -o libadd.so
Wenn Sie die Option "-shared" an den gcc-Compiler übergeben, wird die Objektdatei als gemeinsam genutzte Bibliothek ausgespuckt. Die von Ruby aufzurufende Datei lautet "libadd.so".
add.rb
require 'ffi'
module AddFFI
extend FFI::Library
ffi_lib 'libadd.so'
attach_function :add, [:int, :int], :int
end
puts AddFFI.add(1, 2)
Laden Sie die soeben generierte gemeinsam genutzte Bibliothek mit der Methode ffi_lib
.
Ordnen Sie dann mit attach_function
die im C-Programm definierte Funktion zu, damit sie von Ruby aus verarbeitet werden kann.
Geben Sie dem ersten Argument den Methodennamen, dem zweiten Argument den Argumenttyp der in C definierten Funktion und dem dritten Argument den Rückgabetyp.
Der Methodenname muss mit der im C-Programm definierten Funktion übereinstimmen.
Führen Sie diese Ruby-Datei aus.
$ ruby add.rb
3
Ich konnte das C-Programm erfolgreich über FFI aufrufen.
Das Übergeben als Referenz ist ein Mechanismus zum Teilen des Werts einer Variablen durch Übergeben der Speicheradresse der Variablen. Der Wert wird nicht kopiert. Wenn Sie also die Informationen zu dieser Variablen am Referenzziel neu schreiben, ändert sich auch der Wert der ursprünglich gehaltenen Variablen.
[Zusatz] ~~ Das Übergeben als Referenz ist ein Mechanismus zum Teilen des Werts einer Variablen durch Übergeben der Speicheradresse der Variablen. Der Wert wird nicht kopiert. Wenn Sie also die Informationen zu dieser Variablen am Referenzziel neu schreiben, ändert sich auch der Wert der ursprünglich gehaltenen Variablen. ~~ Das Verständnis des Autors, als Referenz zu gelten, war falsch, und @shiracamus und @ c-yan wiesen darauf hin. Informationen zur Definition des Wortes "Referenzübergabe" finden Sie im Kommentarbereich dieses Artikels. (Danke für den Hinweis!)
sansyo.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int *p, *q;
p = (int *)malloc(sizeof(int));
*p = 1;
printf("%d\n", *p);
//Hier als Referenz übergeben
// [Nachtrag]Dies wird nicht als Referenz übergeben, sondern als Referenzwert(Siehe Kommentare für Details)
q = p;
*q = 2;
printf("%d\n", *p);
}
Wenn Sie dies tun, werden Sie sehen, dass sich der Wert von "* p" nach der Zuweisung zu "* q" geändert hat.
$ gcc -o sansyo sansyo.c
$ ./sansyo
1
2
Ich möchte eine Funktion definieren, die einen Adresswert (Zeiger) im C-Programm zurückgibt, und den Wert von Ruby abrufen, indem ich auf diese Adresse verweise.
Das erstellte C-Programm lautet wie folgt.
add_sansyo.c
#include <stdio.h>
#include <stdlib.h>
int *calc(int a, int b) {
int *p;
p = (int *)malloc(sizeof(int));
*p = a + b;
printf("sansyo function address = %p\n", p);
return p;
}
int main(int argc, char *argv[]) {
int *q = calc(1, 2);
printf("calc(1, 2) = %d\n", *q);
printf("calc(1, 2)'s address = %p\n", q);
}
Zum Debuggen wird calc
in main
aufgerufen.
Ich möchte den Adresswert an Ruby zurückgeben, daher gibt calc einen Zeiger vom Typ int zurück.
Das Ausführungsergebnis ist wie folgt. Es scheint wie beabsichtigt zu funktionieren.
$ gcc -o add_sansyo add_sansyo.c
$ ./add_sansyo
sansyo function address = 0x7f94d54026b0
calc(1, 2) = 3
calc(1, 2)'s address = 0x7f94d54026b0
Konvertieren Sie dieses C-Programm in eine gemeinsam genutzte Bibliothek als add_sansyo.so
und Ruby lädt es.
sansyo.rb
require 'ffi'
module AddFFI
extend FFI::Library
ffi_lib "add_sansyo.so"
attach_function :sansyo, [:int, :int], :pointer
end
result = AddFFI.sansyo(1, 2)
puts result
puts result.read(:int)
ffi
s Repository und rubydoc Ich beziehe mich darauf.
Für das von attach_function
durchgeführte Mapping lautet der Name ebenfalls Zubari, und der Rückgabewert wird in Form von: pointer
angegeben.
Für den Rückgabewert der Methode "AddFFI.sansyo" wird die Klasse "FFI :: Pointer" zurückgegeben, sodass der Wert dieser Adresse von der Instanzmethode "read" erfasst wird.
Wenn es ausgeführt wird, ist es wie folgt, und Sie können verstehen, dass das Ausgabeergebnis der Funktion wie beabsichtigt erhalten werden kann, indem Sie die Adresse berühren, auf die im C-Programm von Ruby verwiesen wird.
$ ruby sansyo.rb
sansyo function address = 0x7fa1aad31860
#<FFI::Pointer address=0x00007fa1aad31860>
3
Mit ffi von Rubygems konnte ich eine in einem C-Programm geschriebene Funktion von Ruby mit einem Wert oder einem Zeiger aufrufen. Ich persönlich mag die Idee, ein Programm durch die Kombination von Sprachfunktionen zu optimieren.
Recommended Posts