12

I'm writing code that will call a C function from Fortran using Fortran's C interoperability mechanism (introduced in Fortran 2003 and implemented in newer versions of gfortran and ifort).

This answer is almost what I need, but I can't quite get my head around what interface declaration I should use in Fortran for a C function that looks like this:

int use_array(int n, char * array[]){
    int i;
    for(i=0; i<n; i++){
        printf("Item %d = %s\n",i,array[i]);
    }
    return n;
}

I'm not clear what the declaration should be for the interface on the Fortran end:

interface
    function use_array(n, x) bind(C)
        use iso_c_binding
        integer (c_int) use_array
        integer (c_int), value :: n
        character(c_char) WHAT_SHOULD_GO_HERE? :: x
    end function use_array
end interface

I do know that I'll have to deal with the null-termination issue too.

francescalus
  • 30,576
  • 16
  • 61
  • 96
JoeZuntz
  • 1,092
  • 10
  • 16
  • Many thanks for user francescalus for helpfully editing this question to make me seem less polite by removing a "thank you" at the end of it. Thank goodness users like them are around to stop people making questions unreadable with everyday courtesy. – JoeZuntz Dec 13 '17 at 12:30

1 Answers1

10

The way we do it is to use a C_PTR array to point to strings. For example:

CHARACTER(LEN=100), DIMENSION(numStrings), TARGET :: stringArray
TYPE(C_PTR), DIMENSION(numStrings) :: stringPtrs

then we set our strings in stringArray, remembering to null-terminate them such as:

DO ns = 1, numStrings
   stringArray(ns) = "My String"//C_NULL_CHAR
   stringPtrs(ns) = C_LOC(stringArray(ns))
END DO

and pass stringPtrs to the C function.

The C function has the interface:

void stringFunc(int *numStrings, char **stringArray) {
    int i;
    for(i=0;i<*numStrings;++i) {
       printf("%s\n",stringArray[i]);
    }
 }
tpg2114
  • 14,112
  • 6
  • 42
  • 57
  • Wonderful, thanks so much for the exceptionally quick and useful reply! For completeness, the type in the interface is then "type(c_ptr), dimension(numStrings)" – JoeZuntz Mar 13 '12 at 15:28
  • Correct, in our code we don't actually provide an interface for the C-function, we treat it as `external` so I didn't have an easy example of the interface block on hand. – tpg2114 Mar 13 '12 at 15:29
  • 2
    This is not standard Fortran 2003 (see section 15.2.1) or 2008 (section 15.3.2): **If the type is character, the length type parameter is interoperable if and only if its value is one.**. And gfortran signals this (using *character(len=...)* with C_LOC) as an error. There is also a [discussion](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36759) on this issue in GCC bugzilla. –  Aug 31 '13 at 18:34
  • An alternative made possible by Fortran 2018 is here: https://fortran-lang.discourse.group/t/return-an-array-of-strings-from-fortran-to-c/5100/7 – K. Shores Jan 30 '23 at 19:58