Pass a real array if a complex array is expected - arrays

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

Related

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.

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

Fortran and C Mixed Programming (Shared Memory)

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.

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

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

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.

Resources