Calling 'C' from FORTRAN

Calling 'C' from FORTRAN

I have inherited some FORTRAN code which makes calls to routines written in 'C' and I keep running into runtime errors where parameters are passed or interpreted incorrectly. I have tried using 'INTERFACE' in the FORTRAN code to ensure parameters are passed consistently but it appears that the INTERFACE needs to be declared in every FORTRAN subroutine that makes the calls to 'C'. If you forget to include it, the code compiles but crashes at run-time because it reverts to the default (by ref) calling convention. This is very hard with large programs and is prone to human error. Is there a way to ensure that all FORTRAN subroutines use the correct calling convention without having to search through and include the INTERFACE statements? Perhaps it is better NOT to do this and to ensure that the 'C' code expects parameters to be passed by reference? This seemed like a reasonable approach to me but the FORTRAN compiler appears to allow different size INTEGERS to be passed so the 'C' code might get a pointer to an INTEGER*2 or an INTERGER*4 and BOOM! more runtime errors.

Any advice on how to do this in a consitent and robust way would be greatly appreciated. Please note that I am a C/C++ programmer and know almost zero about FORTRAN (but willing to learn)

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

Take a look at the Intel Fortran samples for mixed-language programming:

Quote:

User and Reference Guide for the Intel® Fortran Compiler 14.0

Using the Intel® Fortran Samples

The following applies to Fortran for Microsoft Visual Studio* 2010 and 2008.

The Intel® Fortran Compiler installs a number of sample programs. These programming samples illustrate a variety of concepts such as:

 

  • Creating console applications

  • Creating QuickWin applications

  • Creating Win32 applications

  • Using mixed-language support

  • Using OpenGL* in Fortran applications

 

The programming samples are located in the<install-dir>\Samples\ directory. These samples have associated build files that use the Intel® Fortran Compiler, in command-line mode, to compile and build the Fortran sources.

For further information on the samples and how to use them, use a web browser to open and read the samples.htm document in the \Samples\ folder.

Parent topic: Using Microsoft* Visual Studio* (Windows* OS)

Submit feedback on this help topic

Also, look at the documentation in "User and Reference Guide for the Intel Fortran Compiler" under Compiler Reference, Mixed Language Programming.

Thanks FortranFan,

I have used the INTERFACE statement as shown in the samples and it works OK.But unless I am missing something, I have to include this statement in envery subroutine which calls the 'C' code. If I dont, then it reverts to calling the 'C' in the default way (arguments by ref). Since the application is quite large, consisting of may subroutines in several fines, and I did not write it, it is very difficult to catch every instance where the 'C' code is called. In 'C', I would include a header containing function prototypes at the top of every source file and the compiler would highlight 'offending' calls. I tried to put the interface definition in a file and have a single INCLUDE at the top of each fortran source file but the compiler didnt like it. It says "error #6218: This statement is positioned incorrectly and/or has syntax errors" at the first subroutine in the file. Am I doing something wrong?

Sorry but I am not en experienced FORTRAN programmer!

You're correct, the INTERFACE has to be placed at the correctly in each Fortran procedure.   I would think  you would try putting it in a MODULE which you can USE in each procedure, although it could be done by repeating INCLUDE if you observe the position requirements (same as if each procedure were in a separate file).

Best Reply

Tony,

To expand on Tim Prince’s comments, I prefer to use MODULEs instead of INCLUDEs – the choice is yours.  If you use INCLUDEs, you need to pay attention as to where you place them since it works somewhat as a preprocessor in C.

Below is some pseudo-code that shows how you can use MODULEs.  You can see to Intel’s User and Reference Guide for Fortran or refer to any of the books in Dr. Fortran’s blog for details.

Say you have a C function with the following prototype:

   int My_C_Func(char *string, int i, double d[10], void *m);

You can add an interface for it in a Fortran MODULE like this:

   MODULE Interface_to_C_Func
 
      INTERFACE
   
         FUNCTION Cfunc(string, i, d, p) BIND(C, NAME="My_C_Func")
 
            USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_INT, C_CHAR, C_PTR, C_DOUBLE
         
            !.. Return value
            INTEGER(C_INT) :: Cfunc
                  
            !.. Argument list
            CHARACTER(KIND=C_CHAR)     :: string(*)
            INTEGER(KIND=C_INT), VALUE :: i
            REAL(KIND=C_DOUBLE)        :: d(10)
            TYPE(C_PTR), VALUE         :: p
      
         END FUNCTION Cfunc
         
      END INTERFACE
 
   END MODULE Interface_to_C_Func

You can then “use” it in your Fortran procedures as follows:

   FUNCTION My_Fortran_Func(..)
 
      USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_INT !.. Add other objects as needed
      USE Interface_to_C_Func, ONLY : Cfunc
   
      ...
   
      INTEGER(KIND=C_INT) :: CFuncResult
   
      ...
   
      CFuncResult = Cfunc(string, i, d, p)
   
      ...
   
      RETURN
 
   END FUNCTION My_Fortran_Func
 
   SUBROUTINE My_Fortran_Routine(..)
 
      USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_INT !.. Add other objects as needed
      USE Interface_to_C_Func, ONLY : Cfunc
   
      ...
   
      INTEGER(KIND=C_INT) :: CFuncResult
   
      ...
   
      CFuncResult = Cfunc(string, i, d, p)
   
      ...
   
      RETURN
 
   END SUBROUTINE My_Fortran_Routine

Thanks FortranFan and Tim, your help is greatly appreciated.

Leave a Comment

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