Jak uzyskać dostęp (dynamicznie przydzielane) tablice Fortran w C

Moje główne pytanie brzmi, dlaczego tablice robią takie dziwne rzeczy i czy w ogóle istnieje sposób, aby zrobić to w „czysty” sposób.

Obecnie mam program w Cfoo.c połączenie programu Fortranbar.f90 przezdlopen/dlsym, mniej więcej tak jak w poniższym kodzie:

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

Uruchamianie głównych zbiorów

0.0000000000000000        3.1400000000000001        6.2800000000000002        9.4199999999999999     
0.000000 -nan 0.000000 0.000000 

który pokazuje, że Fortran poprawnie alokuje tablicę i nawet poprawnie zapisuje podane wartości, ale nie są one już dostępne przez dlsym (praca nad tymi danymi powoduje segfaults). Wypróbowałem to również dla tablic o stałych rozmiarach - wyniki pozostają takie same.

Czy ktoś zna powód takiego zachowania? Osobiście oczekiwałbym, że rzeczy albo będą działały dwukierunkowo, albo alternatywnie wcale - to „Fortran akceptujący tablice C, ale nie na odwrót” sprawia, że ​​zastanawiam się, czy popełniłem jakiś podstawowy błąd w dostępie do tablicy z C w ten sposób.

Drugie (a nawet ważniejsze) pytanie brzmi: jak zrobić dostęp do tablicy w ten sposób „we właściwy sposób”. Obecnie nie jestem nawet pewien, czy trzymanie się interfejsu „Fortran jako .so” w ogóle jest dobrym sposobem - myślę, że w tym przypadku można byłoby również spróbować programowania mieszanego. Niemniej jednak problemy z tablicami pozostają - przeczytałem, że można to jakoś rozwiązać za pomocą ISO C Binding, ale nie mogłem się jeszcze dowiedzieć, jak to zrobić (jeszcze nie pracowałem zbyt dużo z Fortranem, zwłaszcza w przypadku Binding) , więc pomoc w tej sprawie byłaby bardzo mile widziana.

Edytować:

Dobra, więc trochę więcej czytam w ISO C Binding i znalazłem całkiem przydatne podejścietutaj. Za pomocąC_LOC Mogę uzyskać wskaźniki C do moich struktur Fortran. Niestety, wskaźniki do tablic wydają się być wskaźnikami do wskaźników i należy je wyreferencjonować w kodzie C, zanim będą mogły być traktowane jako tablice C - lub coś takiego.

Edytować:

Teraz mój program działa, używając wiązania C w sposób, który wskazał Vladimir F, przynajmniej w większości. Pliki C i Fortran są teraz połączone ze sobą, więc mogę uniknąć interfejsu libdl, przynajmniej dla części Fortran - wciąż muszę załadować dynamiczną bibliotekę C, uzyskać wskaźnik funkcji do jednego z symboli i przekazać to jako wskaźnik funkcji do Fortrana, który później wywołuje tę funkcję w ramach obliczeń. Jak wspomniano funkcja oczekuje podwójnie * s [tablice], nie udało mi się przekazać moich tablic Fortrana za pomocą C_LOC, co dziwne - aniC_LOC(array) aniC_LOC(array(1)) przekazał poprawne wskaźniki z powrotem do funkcji C.array(1) zrobiłem sztuczkę. Niestety, nie jest to „najczystszy” sposób. Jeśli ktoś ma dla mnie podpowiedź, jak to zrobić, używającC_LOC funkcja, która byłaby świetna. Niemniej jednak akceptuję odpowiedź Vladimira F, ponieważ uważam to za bezpieczniejsze rozwiązanie.

questionAnswers(2)

yourAnswerToTheQuestion