Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

C fortran interoperability. Changing a value in C and pass to fortran's main program.

glp40hs
Beginner
574 Views

Dear,
I want to send a value to a subroutine in c. In subroutine C the value needs to be changed and that change should be kept in fortran. But not work. What do i do?

I greatly appreciate the help!

See example:

---------MAIN FORTRAN---------

program f90callC
use, intrinsic :: iso_c_binding
use interop
implicit none
byte :: i
integer(c_int) :: n
integer(c_int), allocatable, dimension(:) :: vetor
real(c_double) :: val
real(c_float), allocatable, dimension(:) :: array

n=3;   val=3.14
allocate(vetor(n))
allocate(array(n))

write(*,*)'               before:',val
write(*,*)'      ----------------------'
write(*,*)'        vector      array '

do i=1,n
    vetor(i)=2*i-1
    array(i)=i**sqrt(2.)-1
    write(*,*) vetor(i),array(i)    
enddo
write(*,*)'      ----------------------'

!void C
call f_function(n,vetor,val,array)

write(*,*)'               after:',val
write(*,*)'      ----------------------'
write(*,*)'        vetor      array '
do i=1,n    
    write(*,*) vetor(i),array(i)    
enddo
write(*,*)'      ----------------------'

deallocate(vetor)
deallocate(array)

end program f90callC

---------MAIN FORTRAN---------

---------MODULE FORTRAN---------

module interop

    interface inter_c_function        
        subroutine f_function(n, vetor, v, array) bind(c, name='c_function')
            use, intrinsic     :: iso_c_binding
            implicit none
            integer(c_int), value :: n
            integer(c_int), dimension(n),intent(inout) :: vetor
            real(c_double),intent(inout) :: v
            real(c_float), dimension(n),intent(inout) :: array
        end subroutine
    end interface
    
end module

---------MODULE FORTRAN---------

---------Subroutine in C---------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


/* Prototype  */
//int fplusint(int k, int m);
float fmultfloat(float k, float m);
//extern void c_function(int n, int *vetor,double v, float *array);

void c_function(int n, int *vetor,double v, float *array) {
int i;
float aux;
    //comandos
    v+=(double)2.0;
    printf( "            Inside C:          %f \n",v);
    for (i = 0; i < n; ++i)
    {
        //vetor+=n;
        vetor=fplusint(n,vetor);                
        aux=(float)v;
        array=fmultfloat(aux,array);
        //array*=(float)v;
        printf( "           %d     %f \n",vetor,array);
    }    
}

int fplusint(int k, int m)
{
    m+=k;    
return m;
}

float fmultfloat(float k, float m)
{
    m*=k;    
return m;
}

---------Subroutine in C---------

0 Kudos
6 Replies
jimdempseyatthecove
Honored Contributor III
574 Views

Fortran passes by reference (pointer) by default (value overrides this).

Your Fortran interface declares v without "value" which is correct.
However, your C function is declared with v as value "double v", which is incorrect.
Change your C function to "double* v" then use one level of indirect on v

*v += 2.0;

Jim Dempsey

0 Kudos
glp40hs
Beginner
574 Views

Dear Jim Dempsey,

It worked! Is it similar to using c_f_pointer (c_loc (par2), par1)? How would?

Thank you

0 Kudos
jimdempseyatthecove
Honored Contributor III
574 Views

Fortran passes scalar and derived type by reference (default behavior). This is the same as a C pointer. Arrays pass the address of the Fortran array descriptor (however an interface can be declared such that the address of the first cell is passed.

>> c_f_pointer (c_loc (par2), par1)? How would?

There is no need to do that kind of confusing programming. c_f_pointer is generally used to produce a FORTRAN pointer to something allocated or referenced originating inside the C code. An example is a pointer to an array allocated in C. The c_f_pointer constructs the FORTRAN array descriptor.

Jim Dempsey

0 Kudos
glp40hs
Beginner
574 Views

Sorry to bother you again. But I need to know how to pass a type fortran to C and
return with new values. I'm new in C. Example:

-- main fortran --
:

TYPE, BIND(C) :: MYFTYPE
    INTEGER(C_INT) :: I, J
    REAL(C_FLOAT),ALLOCATABLE,DIMENSION(:) :: S ! Are wrong. how is correct in bind(c)?
END TYPE MYFTYPE
type(MYFTYPE) :: mytype

allocate(S(3))

write(*,*)"F(input) :",mytype
call croutine(mytype)
write(*,*)"C(output):",mytype

:
deallocate(S)
end Program main

-- module fortran --
:
INTERFACE   
    subroutine croutine(testtype) bind(c, name='routine')
        use, intrinsic     :: iso_c_binding
        implicit none
        TYPE, BIND(C) :: MYFTYPE
            INTEGER(C_INT) :: I, J
            REAL(C_FLOAT),ALLOCATABLE,DIMENSION(:) :: S
        END TYPE MYFTYPE
        type(MYFTYPE),intent(inout) :: testtype
    end subroutine
END INTERFACE
:

-- header c --
typedef struct {
    int m, n;
    float r(10);
} myctype;

-- c --
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intervars.h"

/* C global variables */
myctype MYcTYPE;

void routine(myctype MYfTYPE)
{
<code to change  MYfTYPE's values and return new values to fortran>
}

thanks a lot.

0 Kudos
jimdempseyatthecove
Honored Contributor III
574 Views

Look in the IVF documentation, index, array descriptors. Your struct myctype should be replaced with:

[cpp]
struct IVF_ARRAY_DESCRIPTOR_DIM_t
{
intptr_t nElements;
intptr_t byteStrideBetweenElements;
intptr_t lowerBound;
};
struct IVF_ARRAY_DESCRIPTOR_t
{
void* base;
intptr_t element_size;
intptr_t A0_offset;
intptr_t Flags; // 1=allocated/defined, 2 = no deallocation, 4=contiguous
intptr_t nDims;
intptr_t reserved;
struct IVF_ARRAY_DESCRIPTOR_DIM_t Dims[7];
};
// ...
typedef struct
{
int m,n;
struct IVF_ARRAY_DESCRIPTOR_t ArrayDescriptor;
} myctype;

[/cpp]

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
574 Views

*** CAUTION ***

IVF Array descriptors are not necessarily the same as MS Fortran, nor GFORTRAN, nor xyz Fortran.

For portability, pass the LOC of the first cell of the array and number of cells.

BTW, in FORTRAN, the right most index has the clostes neighbors (backwards from C).

Jim Dempsey

Jim Dempsey

0 Kudos
Reply