Convert fortran-iso-c-binding real variable to real - c

With fortran-iso-c-binding I can interface C functions and get variables of types like
real(c_float)
integer(c_int)
But in the rest of a program I would like to use basic types (simply because I do not want to replace many real variables with real(c_float) variables just because of one interface function)
Is there a safe, platform/compiler independent and reliable way how to cast fortran-iso-c-binding types back to fortran (primitive) types? equivalent to REAL()

The REAL intrinsic is what you want. Or equivalently, simple assignment.
REAL(C_FLOAT) :: r_c
REAL :: r_default
r_default = r_c
If the value being converted is out of range for the destination kind, your program is non-conforming.

Related

Converting Fortran character and logical arrays between default and C-interoperable kinds

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

Fortran interface allowing rank-1 arrays and scalars

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.

Pass a real array if a complex array is expected

I have a Fortran subroutine that expects a complex array like
subroutine foo(cnumbers, n)
integer :: n
complex :: cnumbers(n)
...
end subroutine foo
and later I want to call it like
real :: rnumbers(40)
...
call foo(rnumbers, 20)
However, I get the compiler error:
error #6633: The type of the actual argument differs from the type of the dummy argument.
Of course, this is comprehensible since a real array is not a complex array. But there must be a way to make it work.
Because if the subroutine foo and the call of foo are in different modules and are written down in different Fortran files, then the compiler does not complain, and everything works fine.
Does someone know how to make it work? How to pass a real array if a complex array is expected?
You can either use transfer(rnumbers, ...) to convert the type (a temporary array is likely to be created) or use equivalence to avoid it
real :: rnumbers(40)
complex :: cnumbers(20)
equivalence (rnumbers, cnumbers)
set the value of rnumbers
call foo(cnumbers, 20)
If you need allocatable arrays the equivalence will not work.
You can also use an external subroutine and lie the compiler about the interface and just pass the real array instead of the complex one. It is not standard conforming, but it is sometimes used. See also Gfortran complex actual to real dummy argument

Kind=dp integer size in Fortran90 [duplicate]

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

Use of unlimited polymorphic type for array operation in Fortran 03/08 (gfortran compiler)

I'd like to realize useful array operations (add element, remove element, different realizations by allocatable/pointer/binary tree structures) by class(*) feature (unlimited polymorphism). I use gfortran 5.0 that should handle such a feature. I need it for not repeating identical code for each type I use.
This should look something like
function add_element(array,element)
class(*),intent(in)::array(:)
class(*),intent(in)::element
class(*)::add_element(size(array)+1)
add_element=[array,element]
end function
The problem is that when I try to use this function with some definite type, I have an error with returning result. I can not assign class(*) to some definite type variable without select type, and I surely don't want to have select type structures every time I use it. And inside a subroutine I should not know anything of types I want to use, because I will create many of them.
I tried some variants with move_alloc, source, tried to use subroutine with intent(out) argument etc. It didn't work. I think it should be defined in argument attributes, the same as size (with source keyword?) but didn't find an example or a definition of such structure in standard. Of course I will study this standard more (I'm not a professional programmer but physicist trying to make my programs testable, checkable and more comfortable to change) and will simply repeat this code now in waiting for better solution, but maybe anybody knows where to search it in the standard or some book? I think this is not only about arrays but use of class(*) at all as I think there should be methods that don't know of types...
Don't know if I should add examples of other not working forms of this subroutine or what it says about the error - or a question will be unfocused. It can be compiled, but in all cases assigning to definite type in call doesn't work. For argument intent(out) or (inout) it can not go from dummy argument to actual argument. Reallocation from source makes an object which has type (and a result of assigning in my example too), but the type is hidden... and I can't use the select type in subroutine because I don't know the type.
Also I don't know constructs that could check "the same type as" or something in this context...
This is not an easy problem You can use select type, but Fortran doesn't have anything like type is(type_of(x)). On the other hand, there are the SAME_TYPE_AS() and EXTENDS
TYPE_OF() intrinsics, but you cannot use them as type guards.
It is necessary to assure, that the dynamic types of both array and element are the same.
I think this is a deficiency in the standard.
But still, there is an error in your approach. You should make the function result allocatable, to be able to allocate it to correct dynamic type:
class(*), allocatable ::add_element(:)
You may think something along the lines of: (UNTESTED! compiles with gfortran-4.9 ifort14)
allocate(add_element(size(array)+1), mold=array)
But how to actually transfer the values I don't know and I am worried it might not be possible without resorting to some dirty tricks.
You cannot even use transfer and that is where I see real deficiency. Eventhough you can call transfer with polymorphic mold
transfer(element, add_element(1))
you have no way to assign it to the array element
add_element(1) = transfer(element, add_element(1))
My opinion is that Fortran lacks an option for the type guards that just ensures that two variables have the same dynamic type.
You may think something along the lines of: (UNTESTED! compiles with gfortran-4.9 ifort14)
function add_element(array,element)
use iso_c_binding
implicit none
class(*),intent(in)::array(:)
class(*),intent(in)::element
class(*), allocatable ::add_element(:)
type(c_ptr) :: tmp
interface
function memcpy(dest, src, n) bind(c)
use iso_c_binding
integer(c_intptr_t),value :: dest, src
integer(c_size_t) :: n
type(c_ptr) :: memcpy
end function
end interface
allocate(add_element(size(array)+1), mold=array)
tmp = memcpy(loc(add_element(size(array)+1)), &
loc(array), &
size(array, kind=c_size_t) * storage_size(array, c_size_t)/8_c_size_t )
tmp = memcpy(loc(add_element(size(array)+1)), &
loc(array(1)), &
storage_size(element, c_size_t)/8_c_size_t )
end function
CLASS(*) is a facility that basically allows runtime type safe but type agnostic storage. You are trying to use it as a compile time type parameterisation mechanism. It isn't terribly appropriate for that, and the language doesn't directly support an alternative means.
Traditionally type parameterisation is done by placing the common parts of the procedures to be parameterised in a separate file, and then including that file as appropriate, perhaps in a module that uses implicit typing to specify the type to be parameterised.
If you must use CLASS(*), you practically need to write and use a wrapper type. If all you are wrapping is basic array operations, then this will be far more trouble than it is worth.
In client code (versus your common procedures) to extract the thing that has been stored you generally need to use SELECT TYPE (you can use pointer assignment if the type of the data has BIND(C) or SEQUENCE, but this isn't type safe).
TYPE :: Wrapper
CLASS(*), ALLOCATABLE :: item
END TYPE Wrapper
FUNCTION add_element(array, element)
TYPE(Wrapper), INTENT(IN) :: array(:)
CLASS(*), INTENT(IN) :: element
TYPE(Wrapper), INTENT(OUT) :: add_element(SIZE(array)+1)
! If you want to enforce type consistency (at runtime)...
IF (SIZE(array) > 0) THEN
IF (.NOT. SAME_TYPE_AS(array(1)%item, element)) THEN
STOP 'Objects not of same type!'
END IF
END IF
add_element(:SIZE(array)) = array
add_element(SIZE(add_element))%item = element
END FUNCTION add_element
FUNCTION get(scalar)
TYPE(Wrapper), INTENT(IN) :: scalar
CLASS(*), ALLOCATABLE :: get
get = scalar%item
END FUNCTION get
...
TYPE(Wrapper), ALLOCATABLE :: array(:)
array = [ Wrapper :: ]
array = add_element(array, 'cat')
array = add_element(array, 'dog')
DO i = 1, SIZE(array)
SELECT TYPE (item => get(array(i)))
TYPE IS (CHARACTER(*))
PRINT "(A)", item
END SELECT
END DO

Resources