Zugriff auf (dynamisch zugewiesene) Fortran-Arrays in C
Meine Hauptfrage ist, warum Arrays so seltsame Dinge tun und ob es überhaupt eine Möglichkeit gibt, das Folgende auf "saubere" Weise zu tun.
Ich habe derzeit ein C-Programmfoo.c
Anbindung eines Fortran-Programmsbar.f90
überdlopen/dlsym
, ungefähr wie im Code unten:
foo.c:
#include <dlfcn.h>
#include <stdio.h>
int main()
{
int i, k = 4;
double arr[k];
char * e;
void * bar = dlopen("Code/Test/bar.so", RTLD_NOW | RTLD_LOCAL);
void (*allocArray)(int*);
*(void **)(&allocArray) = dlsym(bar, "__bar_MOD_allocarray");
void (*fillArray)(double*);
*(void **)(&fillArray) = dlsym(bar, "__bar_MOD_fillarray");
void (*printArray)(void);
*(void **)(&printArray) = dlsym(bar, "__bar_MOD_printarray");
double *a = (double*)dlsym(bar, "__bar_MOD_a");
for(i = 0; i < k; i++)
arr[i] = i * 3.14;
(*allocArray)(&k);
(*fillArray)(arr);
(*printArray)();
for(i = 0; i < 4; i++)
printf("%f ", a[i]);
printf("\n");
return 0;
}
bar.f90:
module bar
integer, parameter :: pa = selected_real_kind(15, 307)
real(pa), dimension(:), allocatable :: a
integer :: as
contains
subroutine allocArray(asize)
integer, intent(in) :: asize
as = asize
allocate(a(asize))
return
end subroutine
subroutine fillArray(values)
real(pa), dimension(as), intent(in) :: values
a = values
return
end subroutine
subroutine printArray()
write(*,*) a
return
end subroutine
end module
Laufende Haupterträge
0.0000000000000000 3.1400000000000001 6.2800000000000002 9.4199999999999999
0.000000 -nan 0.000000 0.000000
Dies zeigt, dass Fortran das Array korrekt zuordnet und sogar die angegebenen Werte korrekt speichert, aber nicht mehr über dlsym erreichbar ist (die Bearbeitung dieser Daten führt zu Fehlern). Ich habe dies auch für Arrays mit fester Größe versucht - die Ergebnisse bleiben gleich.
Kennt jemand den Grund für dieses Verhalten? Ich persönlich hätte erwartet, dass die Dinge entweder bidirektional oder gar nicht funktionieren - dieses "Fortran akzeptiert C-Arrays, aber nicht umgekehrt" lässt mich fragen, ob es einen grundlegenden Fehler gibt, den ich beim Zugriff auf das Array von C auf diese Weise gemacht habe.
Die andere (und noch wichtigere) Frage ist, wie man Array-Zugriffe wie diese "auf die richtige Weise" ausführt. Momentan bin ich mir nicht mal sicher, ob das Festhalten an der "Fortran as .so" -Schnittstelle überhaupt ein guter Weg ist - ich denke, es wäre in diesem Fall auch möglich, eine gemischte Programmierung zu versuchen. Trotzdem bleibt das Array-Problem bestehen - ich habe gelesen, dass dies irgendwie mit der ISO C-Bindung gelöst werden könnte, konnte aber noch nicht herausfinden, wie (ich habe noch nicht viel mit Fortran gearbeitet, insbesondere nicht mit der besagten Bindung). , also Hilfe zu diesem Thema wäre sehr dankbar.
Bearbeiten:
Okay, also habe ich in der ISO C-Bindung etwas mehr nachgelesen und einen recht nützlichen Ansatz gefundenHier. VerwendenC_LOC
Ich kann C-Zeiger auf meine Fortran-Strukturen bekommen. Leider scheinen Zeiger auf Arrays Zeiger auf Zeiger zu sein und müssen im C-Code dereferenziert werden, bevor sie als C-Arrays behandelt werden können - oder so ähnlich.
Bearbeiten:
Ich habe mein Programm jetzt so eingerichtet, dass es C-Binding verwendet, wie es Vladimir F zumindest größtenteils betont hat. Die C-Datei und Fortran-Dateien sind jetzt miteinander verknüpft, sodass ich die libdl-Schnittstelle zumindest für den Fortran-Teil vermeiden kann. Ich muss noch eine dynamische C-Bibliothek laden, einen Funktionszeiger auf eines der dortigen Symbole abrufen und diesen übergeben als Funktionszeiger auf Fortran, der diese Funktion später als Teil seiner Berechnung aufruft. Da diese Funktion double * s [arrays] erwartet, konnte ich meine Fortran-Arrays seltsamerweise auch nicht mit C_LOC übergebenC_LOC(array)
NochC_LOC(array(1))
hat die richtigen Zeiger an die C-Funktion zurückgegeben.array(1)
habe den Trick gemacht. Leider ist dies nicht der "sauberste" Weg, dies zu tun. Wenn jemand einen Tipp für mich hat, wie man das mit dem machtC_LOC
Funktion, das wäre toll. Trotzdem akzeptiere ich die Antwort von Vladimir F. Ich halte es für die sicherere Lösung.