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*.
Related
Background: GCC 10 removed support for calling subroutines with different typed arguments. My aim is to write an interface that respects both integer, dimension(:) and integer.
(Which means I can't use other options such as embedding the scalar in an array. I have to change the interface)
According to GCC docs:
It is possible to provide standard-conforming code which allows different types of arguments by using an explicit interface and TYPE(*).
and:
Note, however, that TYPE(*) only accepts scalar arguments, unless the DIMENSION is explicitly specified. As DIMENSION(*) only supports array (including array elements) but no scalars, it is not a full replacement for C_LOC. On the other hand, assumed-type assumed-rank dummy arguments (TYPE(*), DIMENSION(..)) allow for both scalars and arrays, but require special code on the callee side to handle the array descriptor.
In the interface below I have type(*), dimension(:) :: data. How can I change it according to the text I've emphasized above?
module z
interface
subroutine a(data)
type(*), dimension(:) :: data
end subroutine a
end interface
contains
subroutine b(data)
integer :: data
call a(data)
end subroutine
subroutine c(data)
integer, dimension(:) :: data
call a(data)
end subroutine
end module
Godbolt playground
I am not aware of GCC 10 removing anything (what is your source for that?) but exactly for the reasons you mention, GCC also introduced the directive
!GCC$ attributes no_arg_check::A
(see Procedure for any type of array in Fortran )
which was already used in other compilers that enables the procedure to be called with any arguments, scalars or arrays of any rank, mainly for routines that accept buffers of any type, particularly in MPI libraries.
The new DIMENSION(..) is not really suited for use within Fortran, it requires special code that understands the standard Fortran array descriptor and it is mainly expected that it will be written in C. However, according to the very page you linked https://gcc.gnu.org/onlinedocs/gfortran/Further-Interoperability-of-Fortran-with-C.html#Further-Interoperability-of-Fortran-with-C gfortran does not yet support the standard array descriptor.
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();
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 have long fortran code that has to be made usable from python. I decided to do Fortran->C->Python interface.
I got a problem: I have derived types within Fortran modules that contain
double precision, allocatable
type as members.
When trying to compile with ifort I get (with gfortran something similar):
Each component of a derived type with the BIND attribute shall be a nonpointer,
nonallocatable data component with interoperable type and type parameters
This is actually with agreement with Intel compiler documentation and Fortran 2003 standard: point 15.2.5.
Is there any way to access Fortran "type" with allocatable or pointer inside?
Not really. Even the brand new TS 29113
does not offer a solution. It has the TYPE(*) but you have to know, how to decode the structure in C. You can do it by reverse engineering.
There is actually a macro for the size of the structure in the referenced TS. See CFI_attribute_allocatable. But the problem with dereferencing remains. There is a standard array descriptor proposed, but this TS is not yet supported by some compilers (notably by gfortran).
What is possible, is to just pass the pointer to the structure to a generic function such as qsort. Then you use just a piece of memory, that happens to contain also some pointer or allocatable descriptor, but C does not have to know about them.
Another possibility is to construct a derived type which holds only type(c_ptr), instead of Fortran pointers and use c_loc() to fill them. Be sure to have only contiguous arrays then.
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.