I've been held up on this for about a week, now, and have searched forum after forum for a clear explanation of how to send a char* from C to FORTRAN. To make the matter more frustrating, sending a char* argument from FORTRAN to C was straight-forward...
Sending a char* argument from FORTRAN to C (this works fine):
// The C header declaration (using __cdecl in a def file):
extern "C" double GetLoggingValue(char* name);
And from FORTRAN:
! The FORTRAN interface:
INTERFACE
REAL(8) FUNCTION GetLoggingValue [C, ALIAS: '_GetLoggingValue'] (name)
USE ISO_C_BINDING
CHARACTER(LEN=1, KIND=C_CHAR), DIMENSION(*), INTENT(IN) :: name
END FUNCTION GetLoggingValue
END INTERFACE
! Calling the function:
GetLoggingValue(user_name)
When trying to use analogous logic to return a char* from C, I get problem after problem. One attempt that I felt should work is:
// The C declaration header (using __cdecl in a def file):
extern "C" const char* GetLastErrorMessage();
And the FORTRAN interface:
INTERFACE
FUNCTION GetLastErrorMessage [C, ALIAS: '_GetLastErrorMessage'] ()
USE ISO_C_BINDING
CHARACTER(LEN=1, KIND=C_CHAR), DIMENSION(255), :: GetLastErrorMessage
END FUNCTION GetLastErrorMessage
END INTERFACE
(I can't literally use the DIMENSION(*), so I've gone oversize to 255.)
This should return a pointer to an array of 255 C-style characters - but if it does, I've been unable to convert this to a meaningful string. In practice, it returns a random set of characters, anywhere from Wingdings to the 'bell' character...
I've also attempted to return:
- A pointer to CHARACTER(LEN=255, KIND=C_CHAR).
- Literally CHARACTER(LEN=255, KIND=C_CHAR).
- A INTEGER(C_SIZE_T), and tried to finesse that into a pointer to a string array.
- A CHARACTER.
- etc.
If anybody can give me an example of how to do this, I would be very grateful...
Best regards,
Mike
My thanks to heraldkl for giving me the solution to this very frustrating problem. I'm posting what I've eventually implemented, which roles the pointer conversion into the interface, meaning the final application can call the C function without having to know about the pointer conversion:
The C function:
The FORTRAN interface module:
And to call this function from a FORTRAN program:
My thanks again to heraldkl for providing this solution - I wouldn't have had a clue how do do this without his input.
This thread is a little old, but since I had a similar problem (and probably others will), I post a answer anyway.
The codes posted above will cause a segmentation fault if, for some reason, the C string is null. In addition, there is no need to return a 255-chars string (which will probably need to be trimmed before used), as Fortran 2003/2008 supports functions returning allocatable entities. Using all the information posted above, I ended up with the following function, which gets a C string (pointer), and returns the corresponding Fortran string; If the C string is null, it returns "NULL", similarly to C's "(null)" printed in similar cases:
In Fortran the item needs to be declared as "character (kind=c_char,len=1), dimension (255)" rather than len=255. This will create an array of characters of length one, which is what you need on the C-side. What can be confusing is that there is a exception that allows Fortran to match strings against one-dimensional arrays.
You mean that you want to call a Fortran procedure from C? See this example: Calling a FORTRAN subroutine from C.
EDIT: Both ifort and gfortran say that arrays are not allowed as function returns in this context. Which makes returning strings as function arguments from C to Fortran harder than using a string as an argument (example in link above) ... you have to use pointer and then the c_f_pointer Fortran intrinsic to convert from the C-string to a Fortran string, as explained by haraldkl. Here is another code example:
I always struggle with these interoperability features. I think that your interface should declare
and that, when you call the function, you pass a corresponding Fortran character variable with a length equal to or greater than the length of the array of C characters you expect to return.
Since you seem to have Intel Fortran, look through the code samples provided, they give a complete example for this.
I guess you know that what you have posted is not syntactically correct Fortran ?
Strings of dynamic length are always a bit tricky with the C interaction. A possible solution is to use pointers.
First a simple case, where you have to hand over a null-character terminated string to a C-Function. If you really pass the string only in, you have to ensure to finalize it with the c_null_char, thus this direction is pretty straight forward. Here are examples from a LuaFortran Interface:
And the interface of lua_getfield looks like:
And the C-Code interface is:
Now the little more complex case, where we have to deal with a returned string from C with a dynamic length. The most portable solution I found so far is using pointers. Here is an example with a pointer, where the string is given by the C-Routine (also from the Aotus library mentioned above):
where lua_tolstring has the following interface:
Finally, here is an attempt to clarify how a c_ptr can be interpreted as a Fortran character string: Assume you got a c_ptr pointing to the string:
And the length of it is given by a len variable with the following type:
You want to get this string in a pointer to a character string in Fortran:
So you do the mapping:
I have also struggled with calling a C routine that returns a string and the answers above has been very useful but as I know almost nothing of C and the answers are slightly confusing I just wanted to contribute my solution which uses a C pointer, I did not manage to make use any of the other proposals above. The C program I call opens a separate window to browse for a file name.
Hopefully this example will make it easier for the next one with the same problem.