I'm bridging some legacy code between fortran and C using the iso-c-binding and modules/interfaces etc.
Normally, when passing a fortran array to C I'd just copy it into another array of the right iso-c-binding type. However some of the code requires me to pass a large (multi GB) array. In this case copying it is not sensible. Also, since it is coming from 3rd party code, changing the type of the fortran array no use real(c_float) is not possible either.
However I'd be happy to throw an exception, or fail to compile if the underlying fortran array was incompatible with the C float based API.
Is there a way to check whether a default real is compatible with a C float or double at compile time (or runtime)?
I'm using the intel fortran and C compilers if that matters.
The comparison between the kind of default REAL and the kind of REAL that is interoperable with a float in C is just a simple integer comparison.
You can make this comparison trigger a compile error or runtime error.
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_FLOAT
! -99 is never a valid kind - so this will fail at compile time
! if the test condition is false.
REAL(MERGE(KIND(1.0), -99, C_FLOAT == KIND(1.0)) :: dummy
or
IF (C_FLOAT /= KIND(1.0)) &
ERROR STOP 'Default REAL isn''t interoperable with FLOAT!!'
C_FLOAT itself may have a negative value if the Fortran processor has no kind of REAL that interoperates with it.
(For some 15.0.x versions of ifort the following can be used for the compile time check variant:
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_FLOAT
INTEGER, PARAMETER :: dummy_rk = MERGE(C_FLOAT, -99, KIND(1.0) == C_FLOAT)
! -99 is never a valid kind - so this will fail at compile time
! if the test condition is false.
REAL(dummy_rk) :: dummy
There are several problems.
C's float is passed as a double for C function parameters and expression evaluation. This is easily overcome by passing a pointer to a structure or array containing variables defined as float (which really uses a 32-bit float).
Intel's Fortran has several flavors of real: real*4, real*8, and real*16. By default (compiler settings may change these), real is real*4 and double precision is real*8. See the documentation.
C's long double type has no equivalent in Intel Fortran, where—if it were implemented, would be real*10—which it does use for intermediate values of expressions on an x86.
Of course there is the major column versus minor column array layout problem (for more than one dimensional arrays) of C vs. Fortran.
If it were me, I would blaze the way for development by creating a test which passes known data (1.0, 2.0, 3.0, 4.0, ...) from C to Fortran and vice versa and either print the values or compare them to what they should be. If non-whole numbers are used, be sure to use an appropriate epsilon comparison:
if (abs (c_val - fortran_val) > 0.00001) error();
Related
I am wrapping some legacy F77 code (that I cannot alter) in a C interface. Suppose the legacy code has
subroutine foo(s, l)
character*10 s
logical l(10)
…
I'm writing a small F2008 wrapper foo_wrapper that intends to expose a C-compatible interface through ISO_C_BINDING, do any necessary type conversions, call foo, and finally type-convert back again. My understanding is that I should start out with
subroutine foo_wrapper(c_s, c_l) bind(C, name="foo_wrapper")
use ISO_C_BINDING, only: C_CHAR, C_BOOL
character(kind=C_CHAR, len=1), dimension(10) :: c_s
logical(kind=C_BOOL) c_l(10)
…
but how do I actually do the conversion from c_s into a character*10, and likewise for c_l into a logical (and back after the call)?
Types with default kind parameters do not necessarily fail to be interoperable. Interoperability is based on the kind number, not the specific use of kind=c_kind, in the declaration. If the kind numbers (and if they have them, the length type parameters) match then the types are the same.
Intrinsic assignment to a variable of intrinsic type of an expression of the same intrinsic type "converts" the kind type parameter as necessary.
A copy-in/copy-out mechanism would be like
<type>(kind=f_kind) f
<type>(kind=c_kind) c
c = f
call foo(c)
f = c
where f and c can also be arrays of the same shape as each other.
This always copies. If you want to be more fancy, you can use the techniques in an answer to a related question, using pointers, to copy only if the default and interoperable kinds are not the same.
For real and integer intrinsic types, one may expect default kind parameters (or double precision for the real(kind=c_double)) to be the interoperable ones. Default logical is less likely to be interoperable: Fortran's default logical has the same storage size as default real which probably won't be what C's boolean type has.
Characters also naturally may have interoperable default kind, but you also have to worry about the conversion between the scalar and the array. Again, the technique in the copy/associate linked answer handle this at the same time as the kind conversion.
Consider the program
use, intrinsic :: iso_c_binding
implicit none
print 1, "float", KIND(0e0)==c_float
print 1, "double", KIND(0d0)==c_double
print 1, "int", KIND(1)==c_int
print 1, "char", KIND('')==c_char
print 1, "bool", KIND(.TRUE.)==c_bool
1 format (A,":",T10,L1)
end program
I have a problem with passing of an array from Fortran to a c function:
In the fortran the array is defined as
REAL(KIND=real_normal) , DIMENSION(:), ALLOCATABLE :: array
call cFunc(array)
If define the cFunc as
void cFunc(double *data){...}
Than the data contains only "garbage" values. Where is the problem in this case? (with integers works this solution well).
thx.
EDIT:
My platform:
Compiler: VS 2008, Intel compiler 11 version
OS: Win7
EDIT 2:
I define the interface for the c-function like this (the code is reduced to one element, which makes problems, real function has more parameters):
interface c_interface
subroutine cFunc(array) bind (C, name = "cFunc")
use iso_c_binding
REAL(c_double), DIMENSION(*)::array
end subroutine cFunc
The memory in the fortran is allocated with
ALLOCATE (array(numberOfElements))
call cFunc(array)
At the moment i get an runtime error "Floating-point overflow". In some cases the array correct elements.
The fragment REAL(KIND=real_normal) is not a complete and standard specification of a datatype. Somehwere in the source you have there must be a declaration of the variable real_normal. I'd guess that it is declared such that array is either 4- or 8-byte floating-point numbers, but that is only a guess. What array isn't is an array of default floating-point numbers (called real by Fortran).
As one of the other answerers has suggested, investigate the interoperability with C features of Fortran 2003. If your compiler doesn't implement these, ditch it and get a compiler that does.
#High Performance Mark's suggestions are very good, and I highly recommend the ISO_C_Binding of Fortran 2003 (supported by numerous Fortran compilers) for interoperability between Fortran and C -- there is a larger issue here that makes the ISO_C_Binding more useful: Fortran allocatable arrays are more complicated then ordinary arrays. If you "hack it" and directly pass a pointer to the C code, you are likely to pass a pointer to a Fortran internal structure describing the allocatable array rather than a pointer to the sequence of numeric values. Allocatable arrays aren't directly supported by the ISO_C_Binding, but should work if you write an ISO_C_Binding interface (unlike what I wrote originally) -- the book "Fortran 95/2003 explained" says that the compiler will recognize the the called routine isn't receiving an allocatable array and will perform copy-in/copy-out to match the arrays.
P.S. My guess is that copy-in/copy-out shouldn't be necessary for a simple allocatable actual argument. When the compiler recognizes via an explicit interface (which could be an ISO_C_Binding interface) that the dummy argument of the called routine is not an allocatable, the compiler should just be able to extract the pointer to the actual array from the description of the allocatable and pass that as the argument. Copy-in/copy out will be required in some cases, such as a pointer to a non-contiguous array, such as pointer with a non-unit stride (e.g., a pointer that points to elements 1, 3, 5, ...). But without any interface, the compiler will likely pass the descriptor of the allocatable array, which won't be what C is expecting....
Is real_normal 32-bit or 64-bit floating-point? What happens if you declare the function as void cFunc(float*data) ?
REAL might default to REAL*4 in which case you want a float* instead of double*.
Also make sure that you are prototyping the function before using it, otherwise C has a tendency to auto-promote floats to doubles in the absence of a reason not to. And make sure that you aren't taking a double and then taking an address of it and passing it "as" a float*.
I have an existing Fortran codebase I'm working with and it's quite large. I am no Fortran programmer so I know that I'm not doing everything correctly here.
I'm trying to create and initialize an array of 1.6 million integers. I cannot get this to initialize in Fortran (using ifort or gfort) as I either would have too many line continuations or too long of lines.
So naturally, I switched to C and wrote a function to just initialize an array and it compiles in seconds with no problem. Now I'm trying to link the two together properly. I created a small test case here to simplify things. Here are the three files I'm working with:
init.c
void c_init_()
{
static const int f_init_g[1600000] =
{
3263, 322, 3261, 60, 32249, 32244, 3229, 23408, 252407, 25326,
25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806,
---------------------------------------------------------------------
25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806
};
}
init_mod.f90
MODULE INIT_MOD
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
SAVE
TYPE :: INIT_TYPE
INTEGER (C_INT), DIMENSION(1600000) :: INIT
END TYPE INIT_TYPE
TYPE (C_PTR), BIND(C,NAME="f_init_g") :: INIT_CP
TYPE (INIT_TYPE), POINTER :: INIT_FP
END MODULE INIT_MOD
main.f90
PROGRAM INIT
USE INIT_MOD
USE, INTRINSIC :: ISO_C_BINDING
TYPE (INIT_TYPE) :: INIT_T
CALL c_init()
CALL C_F_POINTER(INIT_CP,INIT_FP)
INIT_T = INIT_FP
END PROGRAM INIT
I compile this using the following commands:
icc -c init.c
ifort -c init_mod.f90
ifort main.f90 init_mod.o init.o
I get a segmentation fault when running because INIT_CP points to nothing as far as I can tell. I know I'm not successfully getting INIT_CP to point at the array in my C function. So I'm trying to figure out how to do that.
I would like if someone has a suggestion on how to initialize this array natively in Fortran. My final option that I'll do is make a small initialization of this array in assembly and write a script to generate the assembly code to initialize this array myself (based off the assembly from the small initialization I can mimic the same thing for any size array). I'm not as excited to do that, but it may be the easiest and most reliable solution.
Most importantly I want other Fortran subroutines that use this array to see that it is static in shape and value so that appropriate inter procedural optimizations can be done.
Fortran-C Interoperable variables must have external linkage. As suggested by others in the comments, move the C declaration to file scope and lose the static specifier.
There is no need for an intermediate C_PTR - a Fortran array variable is directly interoperable with the appropriate C array.
Reducing the size of the array slightly:
/* C File scope */
const int f_init_g[3] = { 101, 102, 103 };
! Fortran
MODULE m
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT
IMPLICIT NONE
INTEGER(C_INT), BIND(C, NAME='f_init_g') :: f_init_g(3)
END MODULE m
PROGRAM p
USE m
IMPLICIT NONE
PRINT *, f_init_g(2)
END PROGRAM p
Note that the starting premise - that it is impossible to define or initialize such an array from within Fortran only - is false. The rules around constant expressions in Fortran permit reference to existing named constants, including named constants that are arrays. If you decide to persist with this madness, and assuming that the value of the initializer cannot be described by some sort of expression, consider:
INTEGER, PARAMETER :: first(10) &
= [ 3263, 322, 3261, 60, 32249, &
32244, 3229, 23408, 252407, 25326 ]
INTEGER, PARAMETER :: second(10) &
= [ 25805, 25723, 25562, 25787, 4549, &
32248, 32244, 32243, 253207, 21806]
...
INTEGER, PARAMETER :: f_init_g(1600000) = [ first, second, ... ]
You will probably need intermediate named constant arrays before the final array constructor.
In the immediate above, f_init_g is a named constant, which is very visible to the compiler, and more likely to result in the optimisations that you seek.
However, you may run into compiler complexity limits, that defeat this latter approach.
When f_init_g is a variable initialized by C, you are basically reliant on the inter-language and inter-procedural optimisation capabilities of your tool set - and if those capabilities even exist, I wouldn't expect much from them for this case. I expect that you aren't going to lose much performance wise, beyond the one-off time for IO, if you read the value of the array in from a file at runtime.
I am calling a C routine from a FORTRAN 90 code. All works fine, but I am wondering why and how when I call the C routine with less parameters that I should the compiler does not complain. What is the compiler doing here? I am using a Cray compiler.
test.c
extern "C" void test_(double* x, double* y, double* z){
// do some work
}
driver.F90
MODULE DRIVER
! declare arrays
DOUBLE PRECISION, DIMENSION(dim, dim), INTENT(IN) :: x
DOUBLE PRECISION, DIMENSION(dim, dim), INTENT(IN) :: y
! call C subroutine
CALL test(x, y)
END MODULE DRIVER
Fortran is a lot different than C when it comes to function calls. When passing arguments to a C routine, the compiler must know the type of each argument, so that it can generate the appropriate calling sequence - either put the arguments on the stack in the correct order and with the correct padding or put them in the expected registers. C compilers usually gather this information when then compile the code if the callee is defined before the caller. In all other cases, a function declaration in the form of a prototype should be provided.
In Fortran all arguments are typically (with some exceptions) passed by address, which means that what actually gets passed to the callee is a set of memory pointers. Pointers look the same - they are always of the same type and hence passed the same way. Therefore a Fortran compiler can generate a function call without knowing what arguments the callee is actually expecting. This greatly simplifies the Fortran compilers but is then a source of myriads of possible errors, like calling a function with the wrong argument types or even with the wrong number of arguments, to name a few. Special programs, called linters (from the name of the C programs verification utility lint), usually have to be used in order to guarantee that no such errors are present. Modern Fortran compilers also try to be much stricter than the older ones and try their best to detect errors whenever possible.
Modern Fortran versions provide the INTERFACE construct that allows explicit declaration of function interfaces, very much similar to function prototypes in C. Module subroutines and functions get their interfaces generated automatically and made available to the callers that USE the module. When calling a subroutine/function with an explicit interface, the compiler is able to verify the validity of the call, i.e. it checks if the number of arguments and their types matches the one in the interface.
You should provide an interface for the external routine and then the compiler would be able to perform the checks. One usually uses the ISO_C_BINDING method in order to interface to C code:
INTERFACE
SUBROUTINE test(x, y, z) BIND(C, NAME="test")
USE, INTRINSIC :: ISO_C_BINDING
REAL(KIND=C_DOUBLE), INTENT(...) :: x ! Put the proper intents
REAL(KIND=C_DOUBLE), INTENT(...) :: y
REAL(KIND=C_DOUBLE), INTENT(...) :: z
END SUBROUTINE test
END INTERFACE
With this interface in place, CALL test(x, y) would result in compile-time error because of argument count mismatch.
I am Fortran beginner and I am trying to adopt some ifort code for compilation with gfortran.
I have problem with the c_loc() function, which in ifort seems to accept dynamic arrays but with gfortran compilation stops with error:
Error: Argument 'septr1' to 'c_loc' at (1) must be an associated scalar POINTER
So does anyone knows how to adapt the following ifort code for compilation with gfortran?
integer(c_int), dimension(:), pointer :: septr1=>null()
type(c_PTR) :: septr
allocate (septr1(10))
septr1 = 33
septr = c_loc(septr1)
This appears to be a requirement from the old Fortran 2003 and relaxed in Fortran 2008. More recent gfortran (5+) accepts this.
You can get the location of the start of the array, the value with offset 0 in C.
septr = c_loc(septr1(1))
or generally not 1 but lbound(septr1).
See the requirements for c_loc argument in Metcalf, Reid and Cohen or in Fortran standard.
It is generally much better to pass the array by reference in normal Fortran way and not to construct an explicit c pointer. For example:
call some_c_function(n,A)
where some_c_function has Fortran interface
interface
subroutine some_c_function(n,A) bind(C)
use iso_c_binding,only: c_int,c_float !you can use also import here
integer(c_int),value :: n
real(c_float),dimension(n):: A
end subroutine some_c_function
end interface
for C prototype
void some_c_function(int n, float* A) //(hope so, I am not so good in C).
ifort developers say that standards compliance checking of c_loc, including its more restricted usage than the legacy LOC(), is not required by the provisions of the Fortran standard.
Possibly in view of the wider scope for useful application of this intrinsic function in current standards, and the need to restrict the scope of uses which need to be tested, most compilers will reject the non-standard usage.