Is it possible to pass fortran 77 function as a callback function pointer to C/C++?
if so, how?
information I found on the web relates to fortran 90 and above, but my legacy code base is in 77.
many thanks
If it can be done in FORTRAN 77, it will be compiler and platform specific. The new ISO C Binding of Fortran 2003 provides a standard way of mixing Fortran and C, and any language that follows or can follow the calling conventions of C, such as C++. While formally a part of Fortran 2003, and while there are extremely few Fortran compilers that fully support the entirety of Fortran 2003, the ISO C Binding is supported by numerous Fortran 95 compilers, including gfortran, g95, Sun, ifort, etc. So I recommend using one of these Fortran 95 compilers and the ISO C Binding method rather than figuring out some method for a particular method. Since FORTRAN 77 is a subset of of Fortran 95, why not compile your legacy code with one of these compilers, using Fortran 95 to add this new feature?
I have called Fortran procedures from C using the ISO C Binding, but haven't passed them as pointers. It should be possible. The steps are:
1) you declare the Fortran function with the Bind(C) attribute,
2) you declare all of the arguments using special types, such as integer(c_int), that match the types of C.
Steps 1 & 2 make the Fortran function interoperable with C.
3) You obtain a C-pointer to this Fortran function with the Fortran instrinsic function "c_funloc", assigning the pointer value to a pointer of type "c_funptr".
4) In the Fortran code, you declare the C routine that you want to pass the function pointer to with an Interface, declaring it in in Fortran terms, but using the Bind(C) attribute and interoperable types so that the Fortran compiler knows to use the C-calling convention -- making the C routine interoperable with Fortran.
Then when you call the C-routine in the Fortran code, you can pass it the function pointer created in step 3.
UPDATE: Code example: The Fortran main program "test_func_pointer" passes a pointer to the Fortran function "my_poly" to the C routine "C_Func_using_Func_ptr" and receives the result back from that C function.
module func_pointer_mod
use, intrinsic :: iso_c_binding
implicit none
interface C_func_interface
function C_Func_using_Func_ptr ( x, Func_ptr ) bind (C, name="C_Func_using_Func_ptr")
import
real (c_float) :: C_Func_using_Func_ptr
real (c_float), VALUE, intent (in) :: x
type (c_funptr), VALUE, intent (in) :: Func_ptr
end function C_Func_using_Func_ptr
end interface C_func_interface
contains
function my_poly (x) bind (C, name="my_poly")
real (c_float) :: my_poly
real (c_float), VALUE, intent (in) :: x
my_poly = 2.0 * x**2 + 3.0 * x + 5.0
return
end function my_poly
end module func_pointer_mod
program test_func_pointer
use, intrinsic :: iso_c_binding
use func_pointer_mod
implicit none
type (c_funptr) :: C_func_ptr
C_func_ptr = c_funloc ( my_poly )
write (*, *) C_Func_using_Func_ptr ( 2.5_c_float, C_func_ptr )
stop
end program test_func_pointer
and
float C_Func_using_Func_ptr (
float x,
float (*Func_ptr) (float y)
) {
return ( (*Func_ptr) (x) );
}
Related
I have a problem understanding why a variable (i) declared in a subroutine is seen in a contained subroutine, but that this is not true for a function (fie) which results in a compilation error. I searched for an answer and also tried to see if I could find something in the Fortran 95 standard but in vain.
I wrote a small example program:
program pgm
call a
end
subroutine a
implicit none
integer :: i
double precision :: fie
i = 7
call b
!write(*,*) fie(9)
contains
subroutine b
double precision :: x
!double precision :: fie
x = i
x = x + fie(i)
write(*,*) x
end subroutine
end subroutine
double precision function fie(ii)
implicit none
integer, intent(in) :: ii
fie = ii
end function
When compiling this with gfortran under cygwin (gfortran 5.4.0) I get the following error message:
$ gfortran aa.f90
aa.f90:20:15:
x = x + fie(i)
1
Error: ‘fie’ at (1) is not a function
When enabling either of the commented lines the program compiles and runs correctly.
I saw a similar error message when using the Intel compiler (Intel Fortran 12.1.7.367, indeed quite old).
It looks like fie has to be made available either in the contained routine or has to be used in the encompassing subroutine, but as said I could not find an answer on the net or in the Fortran 95 standard (or maybe I didn't look for the right words).
Any explanation?
The simplest fix is to use
double precision, external :: fie
the external attribute (also can be specified by the external statement) says: this is a procedure, I am not declaring a local variable.
For the declaration without the external to be interpreted as a function declaration the function reference must be present within the function body. Internal functions don't count. And therefore the compiler created a local double precision variable called fie.
Thank's to IanH for the relevant standard rule (from Fortran 2008 (16.5.1.4p5), but Fortran 95 will have an equivalent):
If an external or dummy procedure with an implicit interface is
accessed via host association, then it shall have the EXTERNAL
attribute in the host scoping unit; if it is invoked as a function in
the inner scoping unit, its type and type parameters shall be
established in the host scoping unit. The type and type parameters of
a function with the EXTERNAL attribute are established in a scoping
unit if that scoping unit explicitly declares them, invokes the
function, accesses the function from a module, or accesses the
function from its host where its type and type parameters are
established.
Of course explicit interfaces (best using modules) are much better than external functions.
I'm trying to use routines in QUADPACK to perform numerical integration. The routines expect functions to be passed as REAL,EXTERNAL, so I don't have the liberty of using pointers or whatever else.
Is it possible to alias a function f(x,a,b,...) as being a function f(x) for the routine that expects a function of x only? Much like what one would accomplish in MATLAB with #(x)f(x,a,b,...).
You cannot make similar tricks with functions in Fortran directly. You also cannot return a closure in Fortran. Just write a wrapper.
function wrap_f(x) result(res)
...
res = f(a,b,...)
end function
It can be an internal or module function and get a and b by the host association or it can use the module containing a and b.
If you want to pass the function as an actual argument, it cannot be an internal procedure in up to Fortran 2003, but only in Fortran 2008. But it works in recent versions of gfortran and ifort. For better portability use a module.
I can show a nice solution for this problem. I am also a former MATLAB user and when switching to FORTRAN you miss function handles haha. I solved your problem in this way:
module
private
public :: f , g
real(kind=RP) :: a0,b0,c0,...
contains
function f(x,a,b,c,d,...)
implicit none
real(kind=RP) :: x,a,b,c,d,...
real(kind=RP) :: f
! Here you define your function
f = ...
end function f
function g(x)
implicit none
real(kind=RP) :: x , g
! Here you call "f" function with the frozen variables *0
g = f(x,a0,b0,c0,...)
end function g
! We said that parameters were private
! (to avoid to be modified from the outside, which can be dangerous,
! so we define functions to set their values
subroutine setValues(a,b,c,...)
implicit none
real(kind=RP) :: a,b,c,...
a0 = a
b0 = b
c0 = c
end subroutine setValues
end module
Currently I am working on a project that requires integrating fortran code to c++. In fortran module lots of variables and arrays are declared. I am able to access the integer,float and double types from c by declaring a c variable as extern double common_area_mp_rmax_ when the corresponding fortran declaration is real*8 rmax and the name of the module is common_area. However, when I try to do the same for an array I am getting error.
suppose the code in fortran module is:
real*8,allocatable,dimension(:,:,:) :: x
I have cretaed a c double pointer as:
extern "C"
{
double* common_area_mp_x_;
}
Now when I compile the whole project, it says "multiple definition of `variable_area_mp_x_'". I am using CMake to compile the whole project.
Can someone shed some light what I am doing wrong? I am new to fortran and it is getting hard for me to fix this. I appreciate your time and help.
Thanks,
mindbender
Fortran 2003 introduced interoperability with C into the standard Fortran language. Unless you have good reasons to the contrary, you should be using the facilities provided by this language feature. See the fortran-iso-c-binding tag on this site for examples.
Under the current Fortran standard (and in the draft of the next standard revision), a Fortran allocatable module variable is not interoperable with a C variable.
In terms of implementation, the Fortran compiler will use a descriptor to store the allocation status of the allocatable variable. There is more to this descriptor than just a pointer to the data - see "Handling Fortran Array Descriptors" in the compiler's User and Reference guide for more information.
The best approach to sharing information in this case depends on what you are trying to do. One option is to give the allocatable array the TARGET attribute, and then have a separate variable of TYPE(C_PTR) with a binding label with the C address of the target. Aspects such as the size of the array would need to be communicated separately.
MODULE common_area
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_DOUBLE
IMPLICIT NONE
...
REAL(C_DOUBLE), ALLOCATABLE, TARGET :: x(:,:,:)
TYPE(C_PTR), BIND(C, NAME='x_ptr') :: x_ptr
CONTAINS
! Call before operating on x_ptr in C++
SUBROUTINE init
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_LOC
ALLOCATE(x(1,2,3))
x_ptr = C_LOC(x)
END SUBROUTINE init
~~~
// After init has been executed, this is a
// pointer to the value of the allocatable module variable
extern "C" double *x_ptr;
Given a C++ file test.cpp with contents
extern "C" { double * foo; }
extern double bar;
double asdf;
with gnu tools
g++ -Wall -c test.cpp; nm test.o
> 0000000000000000 B asdf
> 0000000000000008 B foo
i.e. using the first option actually introduces a new symbol with that name.
In this case the right choice would be
extern double * common_area_mp_x_;
I'm just beginning with Fortran, and I've got a program and a function
PROGRAM multiplication
implicit none
real :: A1
!A1 = mult(2, 3)
!write(*,1) A1
1 format(f8.8)
END PROGRAM multiplication
REAL FUNCTION mult(a, b) BIND(C, name='foomult')
real,value :: a,b
mult = a * b
END FUNCTION
I've got the function working in java through JNA, but when I try to call mult from within the fortran main program, I get a ton of compiling errors (I can provide them if you want). I have a feeling it must be something obvious but I can't find a solution anywhere. Are bound functions not intended to be called from within non-external code? Or do I just have a poor understanding of function syntax?
For the main program, the compiler doesn't "know" the properties of the function, i.e., the types of the function and its arguments. Your function uses an "advanced" argument property, value, so it is necessary to declare the properties in some way to the caller. The easiest way to make those properties known to the caller is to put the function into a module and use that module from a program or procedure that uses it:
module MyModule
contains
FUNCTION mult(a, b) BIND(C, name='foomult')
use iso_c_binding
real (c_float) ,value :: a,b
real (c_float) :: mult
mult = a * b
END FUNCTION
end module MyModule
PROGRAM multiplication
use MyModule
implicit none
real :: A1
A1 = mult(2.0, 3.0)
write(*,*) A1
END PROGRAM multiplication
I've also declared the variables in the function to be compatible with C. It happens, at least with gfortran on my computer, that those are the same as plain real, so they are compatible with the call in the main program. Compatibility could be guaranteed by writing the call as mult (2.0_c_float, 3.0_c_float).
Is it possible in modern versions of Fortran to pass a kind parameter to a subprogram and to use this to 'cast' variables to this kind? As an example, in the following code I am trying to convert an default integer to an 16-bit integer before printing it.
program mwe
! Could use iso_fortran_env definition of int16, but I am stuck with
! old versions of ifort and gfortran.
! use, intrinsic :: iso_fortran_env, only : int16
implicit none
! 16-bit (short) integer kind.
integer, parameter :: int16 = selected_int_kind(15)
call convert_print(123, int16)
contains
subroutine convert_print(i, ikind)
implicit none
integer, intent(in) :: i
integer, intent(in) :: ikind
print*, int(i, ikind)
end subroutine convert_print
end program mwe
With this example code the Intel Fortran compiler complains that
mwe.f(24): error #6238: An integer constant expression is required in this context. [IKIND]
...
mwe.f(24): error #6683: A kind type parameter must be a compile-time constant [IKIND]
and gfortran complains
'kind' argument of 'int' intrinsic at (1) must be a constant
Using print*, int(i, int16) in place of print*, int(i, ikind) would of course work fine in this case. However, if convert_print were defined in a a module which does not define int16 then this would be useless.
Is there a way of passing a kind parameter as a constant to subprograms?
I have the same problem. I find extremely inconvenient that it is not allowed to pass the kind datatype as an argument to a procedures. In my case, I am writing write a subroutine to just read a matrix from a file and get the object in the data type that I want to. I had to write four different subroutines: ReadMatrix_int8(…), ReadMatrix_int16(…), ReadMatrix_int32(…) and ReadMatrix_int64(…) which are nothing but the same code with one single line different:
integer(kind=xxxx), allocatable, intent(out) :: matrix(:,:)
It would make sense to write only one subroutine and pass xxxx as an argument. If I find any solution I will let you know. But I am afraid that there is no better solution than writing the four subroutines and then writing an interface to create a generic procedure like:
interface ReadMatrix
module procedure ReadMatrix_int8
module procedure ReadMatrix_int16
module procedure ReadMatrix_int32
module procedure ReadMatrix_int64
end interface
As far as I can work out, what I am trying to do is expressly forbidden by the Fortran 2003 standard (PDF, 4.5 MB):
5.1.2.10 PARAMETER attribute
A named constant shall not be referenced unless it has been defined previously in the same statement, defined in a prior statement, or made accessible by use or host association.
Therefore is seems that I need to define a function for each conversion I wish to do, for example:
subroutine print_byte(i)
implicit none
integer, intent(in) :: i
print*, int(i, int8)
end subroutine print_byte
subroutine print_short(i)
implicit none
integer, intent(in) :: i
print*, int(i, int16)
end subroutine print_short
subroutine print_long(i)
implicit none
integer, intent(in) :: i
print*, int(i, int32)
end subroutine print_long
Obviously all of the above will have to be overloaded to accept different kinds of the input argument. This seems like a lot of work to get around not being able to pass a constant, so if someone has a better solution I am keen to see it.
This Intel expert gives an explanation and an elegant solution. I couldn't explain it better. A full cite follows:
"One day while I was wandering the aisles of my local grocery store, a woman beckoned me over to a table and asked if I would like to "try some imported chocolate?" Neatly arrayed on the table were packages of Lindt, Toblerone, and... Ghiradelli? I asked the woman if California had seceded from the Union, as Ghiradelli, despite its Italian name, hails from San Francisco. I suppose that from the vantage point of New Hampshire, California might as well be another country, much as depicted in that famous Saul Steinberg 1976 cover for The New Yorker, "View of the World from 9th Avenue".
(I've been warned that my blogs don't have enough arbitrary links - this should hold 'em for a while.)
Similarly, in Fortran (I'll bet you were wondering when I'd get to that), something can be so near yet seem so far away. A short time ago, I was writing a new module for Intel Visual Fortran to provide declarations for the Win32 Process Status API. This would contain declarations of types and constants as well as interface blocks for the API routines, some of which take arguments of the new type. The natural inclination is to write something like this:
MODULE psapi
TYPE sometype
some component
END TYPE sometype
INTERFACE
FUNCTION newroutine (arg)
INTEGER :: newroutine
TYPE (sometype) :: arg
END FUNCTION newroutine
END INTERFACE
END MODULE psapi
If you did and compiled it, you'd get an error that type sometype is undefined in the declaration of arg. "What? It's not undeclared, I can see it right above in the same module!" Well, yes and no. Yes, it's declared in the module and could be used anywhere in the module, except.. Except in interface blocks!
The problem is that interface blocks are a "window into the external routine" - they essentially duplicate the declarations you would see in the actual external routine, assuming that routine were written in Fortran. As such, they do not "host associate" any symbols from the enclosing scoping unit (the module in this case.)
In Fortran 90 and Fortran 95, the typical solution for this was to create a separate module, say, "psapi_types", containing all of the types and constants to be used, You'd then add a USE statement inside each function, just as you would have to in the hypothetical external routine written in Fortran. (If it were written in Fortran, the Doctor would slap your wrist with a wet punchcard and tell you to make the routine a module procedure, and then you wouldn't need to worry about this nonsense.) So you would end up with something like this:
MODULE psapi
USE psapi_types ! This is for the benefit of users of module psapi
INTERFACE
FUNCTION newroutine (arg)
USE psapi_types
INTEGER :: newroutine
TYPE (sometype) :: arg
...
Those of you who use Intel Visual Fortran know that in fact there's a giant module IFWINTY for this purpose, containing all of the types and constants for the other Win32 APIs. It's messy and inelegant, but that's what you have to do. Until now...
Fortran 2003 attempts to restore some elegance to this sorry situation, but to preserve compatibility with older sources, it couldn't just declare that interface blocks participate in host association. Instead, a new statement was created, IMPORT. IMPORT is allowed to appear in interface blocks only and it tells the compiler to import names visible in the host scope.
IMPORT is placed following any USE statements but before any IMPLICIT statements in an interface body (the FUNCTION or SUBROUTINE declaration). IMPORT can have an optional import-name-list, much like USE. Without one, all entities accessible in the host become visible inside the interface body. With a list, only the named entities are visible.
With IMPORT, my PSAPI module can look like the first example with the following change:
...
FUNCTION newroutine (arg)
IMPORT
INTEGER :: newroutine
TYPE(sometype) :: arg
...
I could, if I wanted to, use:
IMPORT :: sometype
to say that I wanted only that one name imported. Nice and neat and all in one module!
"But why are you telling me this?", you might ask, "That's a Fortran 2003 feature and Intel Fortran doesn't yet do all of Fortran 2003." True enough, but we keep adding more and more F2003 features to the compiler and IMPORT made it in back in August! So if you are keeping reasonbly current, you can now IMPORT to your heart's content and do away with the mess of a separate module for your types and constants.
If you want to know what other F2003 goodies are available to you, just check the Release Notes for each update. A full list of supported F2003 features is in each issue. Collect 'em all!"