Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to access (dynamically allocated) Fortran arrays in C
    primarykey
    data
    text
    <p>My main question is why arrays do such weird things and whether there is any way at all to do the following in a "clean" way.</p> <p>I currently have a C program <code>foo.c</code> interfacing a Fortran program <code>bar.f90</code> via <code>dlopen/dlsym</code>, roughly like in the code below:</p> <p><strong>foo.c:</strong></p> <pre><code>#include &lt;dlfcn.h&gt; #include &lt;stdio.h&gt; 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 **)(&amp;allocArray) = dlsym(bar, "__bar_MOD_allocarray"); void (*fillArray)(double*); *(void **)(&amp;fillArray) = dlsym(bar, "__bar_MOD_fillarray"); void (*printArray)(void); *(void **)(&amp;printArray) = dlsym(bar, "__bar_MOD_printarray"); double *a = (double*)dlsym(bar, "__bar_MOD_a"); for(i = 0; i &lt; k; i++) arr[i] = i * 3.14; (*allocArray)(&amp;k); (*fillArray)(arr); (*printArray)(); for(i = 0; i &lt; 4; i++) printf("%f ", a[i]); printf("\n"); return 0; } </code></pre> <p><strong>bar.f90:</strong></p> <pre><code>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 </code></pre> <p>Running main yields</p> <pre><code>0.0000000000000000 3.1400000000000001 6.2800000000000002 9.4199999999999999 0.000000 -nan 0.000000 0.000000 </code></pre> <p>which shows that Fortran allocates the array correctly and even correctly stores the given values but they are not accessible via dlsym anymore (working on that data results in segfaults). I also tried this for fixed-size arrays - the results stay the same.</p> <p>Does anyone know the reason for this behaviour? I, personally, would have expected things to either work out bidirectional or alternatively not at all - this "Fortran accepting C arrays but not vice versa" makes me wonder whether there's some basic mistake I made on accessing the array from C in this fashion.</p> <p>The other (and even more important) question is, how to do array accesses like these "the right way". Currently I'm not even sure if sticking to the "Fortran as .so" interface is a good way at all - I think it would also be possible to attempt mixed programming in this case. Nonetheless, the arrays issue remains - I read that this could be solved somehow using the ISO C Binding, but I couldn't figure out how, yet (I haven't worked a lot with Fortran, yet, especially not with said Binding), so help on this issue would be greatly appreciated.</p> <p><strong>Edit:</strong></p> <p>Okay, so I read into the ISO C Binding a little more and found a quite useful approach <a href="https://stackoverflow.com/questions/9677972/how-to-allocate-an-array-inside-fortran-routine-called-from-c">here</a>. Using <code>C_LOC</code> I can get C pointers to my Fortran structures. Unfortunately, pointers to arrays seem to be pointers to pointers and need to be dereferenced in the C code before they can be treates as C arrays - or something like that.</p> <p><strong>Edit:</strong></p> <p>Got my program to work now using C binding the way Vladimir F pointed out, at least for the most part. The C file and Fortran files are now linked together, so I can avoid the libdl interface, at least for the Fortran part - I still need to load a dynamic C library, get a function pointer to one of the symbols in there and pass that as a function pointer to Fortran, which later calls that function as part of its calculation. As said function expects double*s [arrays], I couldn't manage to pass my Fortran arrays using C_LOC, strangely - neither <code>C_LOC(array)</code> nor <code>C_LOC(array(1))</code> passed the correct pointers back to the C function. <code>array(1)</code> did the trick though. Sadly, this isn't the "cleanest" way to do this. If anyone got a hint for me how to do this using the <code>C_LOC</code> function, that would be great. Nonetheless I accept Vladimir F's answer, as I deem it to be the safer solution.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload