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

passing modules from f90 to C

mhovers
Beginner
791 Views

If I have f90 code that calls C routines, is there a way to pass the contents of a module to the C routines like it was a header file? I dont want to have to put every array in the argument list of the call to the C wrapper.

thanks,

0 Kudos
5 Replies
Steven_L_Intel1
Employee
791 Views
No, there isn't. But you can reference module variables as externs in C. This is discussed in the Fortran documentation for Building Applications > Mixed Language Programming > Sharing Data. You would declare the variable in the C code as an extern of the proper type using the name MODULENAME_mp_VARIABLENAME.
0 Kudos
jimdempseyatthecove
Honored Contributor III
791 Views

In addition to using external variable name as mentioned by Steve the method I often use is to construct a derived type containing the module data

module mod_foo
type someType
sequence
...
end typeSomeType
type someOtherType
sequence
...
end someOtherType
...
type typeFoo
sequence
real :: variable
type(someType):: aSomeType
type(someOtherType)::bOtherType
end type typeFoo

type(typeFoo) :: Foo! the one and only Foo
end module mod_foo

Your Fortran program

program YourProgram
use mod_foo
...
Foo.variable = 1234.56
...
call Csubroutine(Foo)
...
end program YourProgram

Programming Hint

If your program is a conversion of a legacy F77 program (from COMMON to modules) you may find it inconvienent to change all references of "variable" to "Foo.variable" (or "Foo%variable". The technique I use is to enable the Fortran Preprocessor and use a #define to make the conversions automatic. The #defines are then placed into an #include file (not in the module, and not in a Fortran .FI file)

The define macro names are case sensitive --- make use of that.

! mod_foo.def - defines for mod_foo.f90
#define VARIABLE Foo%variable
#define SOMETHING Foo%aSomeType%something
...

Then at the top of the .F90 source file insert

#include "mod_foo.def"

Only include once per source file, usualy at the top of the file.

Often the legacy F77 used all upper case variable names. Therefor, in your derived types you can use lowercase names and not have to worry about conflicting names. If you forget the #include file (and use implicit none) you will have undefined variables at compile time. If you have the #include file and forget the use file you will have undefined variables at compile time. Both cases are easily identifiable and correctable.

Using this technique the same source file can be compiled as was using COMMONs or as intended using MODULES.

! YourProgram
! your comments here
! if _MOD defined use modules else use COMMONS
#ifdef _MOD
#include 'mod_foo.inc'
#endif

program YourProgram
#ifdef _MOD
use mod_foo
#else
INCLUDE'FOO.FI'
#endif
...
! untouched statements Either Foo%variable or VARIABLE from COMMON
A = VARIABLE
...
end program YourProgram

Jim Dempsey


0 Kudos
Steven_L_Intel1
Employee
791 Views
I should also mention that if you share ALLOCATABLE or POINTER arrays in this manner, what you'll be sharing is the array descriptor and not the actual data. The layout of the descriptor is documented.
0 Kudos
jimdempseyatthecove
Honored Contributor III
791 Views

>> I should also mention that if you share ALLOCATABLE or POINTER arrays in this manner, what you'll be sharing is the array descriptor and not the actual data. The layout of the descriptor is documented.

That is correct. Most C/C++ functions (easy way to write) expect the location of the first cell and a count of cells (or count of rows and cols) and do not go to the effort of deciphering the array descriptors (which is subject to change). Prototype:

void Csub(real* r, int n);

Therefore the fortran call would be

call Csub(%LOC(A(1)), size(A))

And consider:

#define CSUB(A) Csub(%LOC(A(1)), size(A))

then in your code you can use

CALL CSUB(SomeArray)

Note, I will leave it as a exercize to construct the CSUB macro such that the array can have dimension range starting at other than 1 and/or of different rank.

The #defines make it relatively easy to maintain identical source code statements while converting legacy code to the "modern" age of modules and cross language applications.

Might Intel consider adding an ATTRIBUTE for use in interface to specify if the address of the descriptor is to be passed or if the address of the first data cell is to be passed. This way there would be no ambiguity as to what is required to be passed

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
791 Views
Jim, I think you misunderstood my post. I was referring only to referencing arrays as externs in C, NOT passing them as arguments. When you pass an array as an argument, how it is passed depends on whether there is an explicit interface and what it says. If there is an interface that declares the dummy argument as assumed shape, DIMENSION(:), then it is passed by descriptor, otherwise it is passed by reference. Typically when calling C routines you'd want pass-by-reference and would use DIMENSION(*) in an interface. (If there is no interface, then DIMENSION(*) is assumed.)
0 Kudos
Reply