Calling Fortran from C

Calling Fortran from C

My Windows application is written primarily in Fortran but calls functions from in C library (which I have access to code). I need to be able to call a Fortran subroutine from within the C library to display error and warning messages the GUI.

The simplest solution seems to be to create a C function, within the C library, that calls a Fortran subroutine which accepts the message as a character array. I found the following text on a web site called XGear but I've not had any joy using this with the Intel compiler.

Fortran functions that receive string variables from C

C

This is slightly more complicated. The Fortran function must be declared at the beginning of the C calling function (e.g. main) like this:

      extern void load_(char *string, size_t *len_string);

Note that we have to pass all variables to Fortran as pointers. Our string variable is already a pointer, but we have to pass the string's length as a pointer too. Although the function name is not case sensitive in Fortran, it gains an underscore in the C declaration and when it is called:

      len_string = strlen(string); 
      load_(string, &len_string);

Note that in passing the string from C to Fortran we also need to pass the length of the string, hence the use of strlen beforehand (not forgetting to declare the string length variable as a size_t rather than an int).

Fortran

The Fortran function has to be modified to receive a string variable as a byte array (instead of a character string), as well as the string's length:

      SUBROUTINE LOAD(string,len_string)
      BYTE          string(51)
      INTEGER       len_string

Note that the original Fortran function would not have needed an integer variable to store the length of the received string. We also have to add the following to our Fortran function so that it copies the byte array to a string:

      CHARACTER*50  charstr
      WRITE (charstr,'(50a)') (string(i),i=1,len_string)

Has anyone any tips on how can this be done using the ISO_C_BINDING which would be the cleanest route but a have not found a good example for a subroutine passing a string from Fortran to C. I have tried several things without success? The main problem is an undefine external symbol. The code would need to apply toboth 32-bit and 64-bit configurations.

Thanks in advance.

 

6 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

It is incorrect that the argument needs to be a "byte array". Indeed, BYTE is not standard. It is true that the argument needs to be an array of single characters and any length passed explicitly. Unfortunately, Fortran doesn't make it easy to pass character strings in this direction. Rather than use WRITE, you could use TRANSFER to copy the data

You will want to add BIND(C) after the argument list in Fortran and remove that trailing underscore in the C routine. Also, in the Fortran routine, the string length should be declared INTEGER(C_INTPTR_T).

Steve - Intel Developer Support

Thanks Steve,

Did you mean INTEGER( C_SIZE_T) rather than INTEGER(C_INTPTR_T)? I got an undefined symbol error and can't find a reference to C_INTPTR_T  in the documentation.

subroutine mgn_message(message,lm) bind(C)
!*********************************************************************
! Send Character string back to FORTRAN
!*********************************************************************
use,intrinsic :: ISO_C_BINDING
use StringLib
implicit none
! Arguments
integer(C_INTPTR_T) ,intent(in),value :: lm
!integer(C_SIZE_T) ,intent(in),value :: lm
character(len=1),intent(in) :: message(lm+1)
! Local variablesahc
character(len=lm+1) :: chastr
integer :: i
if(lm.eq.0) return
! Copy character aarry to string variable
write(chastr,'(<lm>a)') (message(i),i=1,lm)
!chastr = transfer(message,lm)
! Convert C String for Fortran
call str_CstrToF(chastr)
! Send message to oGUI
call grp_message(chastr)
return
end subroutine

I tried the transfer function to copy the character array to string but compiler complains about a mismatch in arguments, what am I doing wrong?

P.S. when I tried to add the code snippet using the {--} button I got an "Error on Page" message. It seemed to work if I added the delimiters manually though.

Try

chastr = transfer(message, chastr)

The 2nd argument to transfer (known as MOLD in the Fortran 2008 standard) determines the type and type parameters of the return value.

No, I meant C_INTPTR_T. C_SIZE_T probably makes more sense, however - for some reason I didn't remember that one.

Steve - Intel Developer Support

Thanks everyone,

With a couple of tweaks to the above code I managed to successfully pass the string from C to FORTRAN. The corrected code is shown below. StringLib refers to my string utility module that contains the function str_CStrToF that is used to remove the char(0) C string termination character. This could be easily substituted by the line message = message(1:index(message,char(0))-1).

subroutine mgn_message(message,lm) bind(C)
!*********************************************************************
! Send Character string back to FORTRAN
!*********************************************************************
use,intrinsic :: ISO_C_BINDING
use StringLib
implicit none
! Arguments
integer(C_SIZE_T) ,intent(in) :: lm
character(len=1),intent(in) :: message(lm+1)
! Local variablesahc
character(len=lm+1) :: chastr
integer :: i
if(lm.eq.0) return
! Copy character aarry to string variable
chastr = transfer(message,chastr)
! Convert C String for Fortran
call str_CstrToF(chastr)
! Send message to GUI
call grp_message(chastr)
return
end subroutine

Leave a Comment

Please sign in to add a comment. Not a member? Join today