views:

338

answers:

3

Basically, here's my problem. I'm calling someone else's FORTRAN functions from my C++ code, and it's giving me headaches. Some code:

function c_error_message()
character(len = 255) :: c_error_message
errmsg(1:9) = 'ERROR MSG'
return
end

That's the FORTRAN function. My first question is: Is there anything in there that would cause a segfault?

If not, then second: What does that return? A pointer? I'm trying to call it with the following C statement:

char *e = c_error_message_();

That causes a segfault.

c_error_message();

That too causes a segfault.

I declared c_error_message_() earlier on with the following code:

extern"C" {
    char* c_error_message_();
}

Would declaring a function with a different return type than the actual return type cause a segfault?

I'm at a loss. Thanks for any replies.

+1  A: 

Since the second line declares a name that is the same as the function name, it is declaring the type of the function return, namely a scaler character string of 255 characters. But in theory this doesn't tell us the internal API -- that is up the the compiler. I don't know where "errmsg" comes from -- it must be declared elsewhere -- perhaps a global variable as suggested by Michael Anderson. Or maybe this is a mistake and the line should be c_error_message = "ERROR MSG". (There is no need to designate the sub-string range -- the rest of the string will be filled with blanks.) IMO, the best approach to calling Fortran from C (or vice-a-versa) is to use the ISO C Binding, which will cause the Fortran compiler to use a C compatible Interface. I haven't done a function returning a string, but have done strings as arguments.

M. S. B.
A: 

FORTRAN functions return the value assigned to the function name. The type returned is specified by the function definition, and in this case, it is returning an character string 255 characters long. I think the type mismatch is why you are segfaulting. So what C type should you use? I don't know.

I found this Using C with FORTRAN page, and the author strongly recommends using FORTRAN subtroutines and calling them as C functions returning type void.

Here is an F95 quick reference.

Fred
The "Using C with FORTRAN page" from 2001 is obsolete and has some incorrect information. For example, the statement that only int/INTEGER, float/REAL and double/DOUBLE can be reliably interchanged is no longer true. In the past connecting languages was compiler and platform specific. With the ISO C Binding of Fortran 2003, Fortran and languages with a C internal interface can be mixed in a standard manner that is not compiler and platform specific.
M. S. B.
+1 Interesting. I did not know that. I haven't written FORTRAN in a long time, and you've obviously kept up!
Fred
+2  A: 

Here is a method that works. When I tried to use the ISO C Binding with a function returning a string, the compiler objected. So if instead you use a subroutine argument:

subroutine fort_err_message (c_error_message) bind (C, name="fort_err_message")

use iso_c_binding, only: C_CHAR, C_NULL_CHAR

character (len=1, kind=C_CHAR), dimension (255), intent (out) :: c_error_message

character (len=255, kind=C_CHAR) :: string
integer :: i

string = 'ERROR MSG' // C_NULL_CHAR

do i=1, 255
   c_error_message (i) = string (i:i)
end do

return

end subroutine fort_err_message

The Fortran is a bit awkward because technically a C-string is an 1D array of characters.

And example C code to demo that this works:

#include <stdio.h>

void fort_err_message ( char chars [255] );

int main ( void ) {

  char chars [255];

  fort_err_message ( chars );

  printf ( "%s\n", chars );

  return 0;

}
M. S. B.
Worked perfectly. Thanks a ton!
Dane Larsen