I have pre-existing code that I am modifying to use the Fortran iso_c_binding standard. I’d like to know how many ways can you do it.
The below program compiles perfectly without any warnings using the iso_c_binding standard but doesn’t work.
Basically originally, on the Fortran side I had an integer defined. This integer got storage for an array via a C malloc. I have a similar variable (but a real) on the Fortran side which gets set to many values. The real is used to set values in what used to be an integer using C. How do I modify the below program to do this with iso_c_binding? Does the Fortran and/or C code have to change?
File main.f90:
program main
use the_interface
use iso_c_binding, only : c_int,c_ptr,c_loc
implicit none
type(myint), pointer :: intvar
type(c_ptr), pointer :: value_ptr
type(real), allocatable, target :: value(:)
type(c_ptr) :: myint_ptr
integer ans,i
allocate(value(10),value_ptr)
value_ptr = c_loc(value)
do i = 1,10
value(i) = real((i-1) * 3 + (i-1),4)
end do
ans = get_storage(myint_ptr)
ans = set_source(myint_ptr,value_ptr)
ans = print_source(myint_ptr)
end program main
File test.c:
#include <stdio.h>
#include <stdlib.h>
typedef int int_type;
struct myint {
int value;
};
#define NUM 10
int get_storage_ (int_type **dest)
{
*dest = (int_type *)malloc(NUM * sizeof(int_type));
if (!*dest) {
return -1;
}
return 0;
}
int set_source_ (struct myint **dest, struct myint *source)
{
int i;
int counter = 0;
for (i = 0;i < NUM;i++)
{
/* (*dest + i)->value = i * 3 + i; */
(*dest + i)->value = (source + i)->value;
if (!(++counter % 5))
{
printf ("\n");
counter = 0;
}
}
return 0;
}
int print_source_ (struct myint **dest)
{
int i;
int counter = 0;
int errors = 0;
for (i = 0;i < NUM;i++)
{
if (((*dest + i)->value) != (i * 3 + i))
{
printf ("Error at %d %d != %d ",i, ((*dest + i)->value),(i * 3 + i));
errors ++;
}
else
{
printf ("Value at %d = %d ",i,(*dest + i)->value);
}
counter++;
if (!(counter % 5))
{
printf ("\n");
counter = 0;
}
}
printf ("\n%d values weren't set correctly!\n",errors);
printf ("%d values were set correctly!\n\n",NUM - errors);
return 0;
}
File the_interface.f90:
module the_interface
use iso_c_binding, only: c_int, c_ptr,c_float
type, bind(c) :: myint
integer(c_int) :: int_tmp
end type
type, bind(c) :: myfloat
real(c_float) :: float_tmp
end type
function get_storage(address)bind(c,name="get_storage_")
import :: c_int, c_ptr, myint
implicit none
type(c_ptr), intent(inout) :: address
integer(c_int) :: get_storage
end function
function set_source(address, value)bind(c,name="set_source_")
import :: c_int, c_ptr, myint
implicit none
type(c_ptr), intent(inout) :: address
type(c_ptr), intent(inout) :: value
integer(c_int) :: set_source
end function
function print_source(address)bind(c,name="print_source_")
import :: c_int, c_ptr, myint
implicit none
type(c_ptr), intent(inout) :: address
integer(c_int) :: print_source
end function
end interface
end module the_interface
Compilation and Run:
gcc -g -c test.c -o test.o
gfortran -g -c the_interface.f90 -o the_interface.o
gfortran -g -c main.f90 -o main.o
gfortran -g main.o test.o -o main.exe -lgfortran
./main.exe
Output:
Error at 0 38195424 != 0 Error at 1 38195424 != 4 Error at 2 38195424 != 8 Error at 3 38195424 != 12 Error at 4 38195424 != 16 Error at 5 38195424 != 20 Error at 6 38195424 != 24 Error at 7 38195424 != 28 Error at 8 38195424 != 32 Error at 9 38195424 != 36