Verwenden Sie das C-Programm von Ruby

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.

Wert übergeben

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.

Übergeben Sie mit einem Zeiger

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!)

Beispiel

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)

ffis 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

Zusammenfassung

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

Verwenden Sie das C-Programm von Ruby
[Flattern] Wie verwende ich C / C ++ von Dart?
Ruby Gehaltsberechnungsprogramm
Ruby Score Berechnungsprogramm
Von Java zu Ruby !!
Verwenden Sie TensorFlow von JRuby
Ruby Numerical Reference Program
Versuchen Sie es mit Cocoa von Ruby
Verwenden Sie Ruby-Variablen in Javascript.
Ruby C Erweiterung und flüchtig
Rbenv-Befehl zur Verwendung von Ruby
Ruby: Wie man Cookies benutzt
[Ruby] Empfangen Sie Eingaben von der Konsole
CHATBOT (Dialogflow) von Ruby
Verwenden Sie Ruby mit Google Colab
Ich habe versucht, eine C-Sprachprogrammquelle aus cURL zu generieren
Schreiben Sie Ruby-Methoden mit C (Teil 1)
Verwendung von Ruby on Rails
[Ruby] Entkomme aus mehreren Schleifen [Nest]
Verwenden Sie Chrome Headless von Selenium / Java
Einführung in Ruby (aus anderen Sprachen)
Verwenden Sie benutzerdefinierte Datenbankfunktionen von JPQL
Verwendung der Ruby-Inject-Methode
Rufen Sie C-Sprachfunktionen von Swift aus auf
[Ruby / Refactoring] Von der iterativen Ruby-Verarbeitung wie Java und C bis zur Ruby-ähnlichen iterativen Verarbeitung