Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Calling 'C' from FORTRAN

Tony_D_
Beginner
3,009 Views

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)

0 Kudos
1 Solution
FortranFan
Honored Contributor II
3,009 Views

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:

[cpp]

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

[/cpp]

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

[fortran]

   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

[/fortran]

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

[fortran]

   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

[/fortran]

View solution in original post

0 Kudos
5 Replies
FortranFan
Honored Contributor II
3,009 Views

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

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.

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

0 Kudos
Tony_D_
Beginner
3,009 Views

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!

0 Kudos
TimP
Honored Contributor III
3,009 Views

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).

0 Kudos
FortranFan
Honored Contributor II
3,010 Views

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:

[cpp]

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

[/cpp]

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

[fortran]

   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

[/fortran]

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

[fortran]

   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

[/fortran]

0 Kudos
Tony_D_
Beginner
3,009 Views

Thanks FortranFan and Tim, your help is greatly appreciated.

0 Kudos
Reply