Iso_c_binding C routine call with pointers from Fortran with arrays

I dug up on the forum looking for a solution, but I failed. My main problem is that I'm too noob with C language and Fortran-C compatibility to understand what I'm doing wrong.

I want to call the C routine from Fortran, but I have a problem with declaring variables. I made an example.

This is the C routine:

#include <stdio.h> #include <stdlib.h> #include <math.h> #include <complex.h> #undef I int photon_trace(double x_init[4], double x_final[4]) //*************************************************** { double r,m,t,phi; t = x_init[0]; r = x_init[1]; m = x_init[2]; phi = x_init[3]; t=t+1.0; r=r+1.0; m=m+1.0; phi=phi+1.0; x_final[0] = t; x_final[1] = r; x_final[2] = m; x_final[3] = phi; return 0; } 

This is the main program in Fortran:

 program main_dummy ! compile: f95 raytracing.f90 main_dummy.f90 dummy_trace.o -o main use, intrinsic :: ISO_C_BINDING use raytracing implicit none real(C_FLOAT), dimension(0:3) :: x_in, x_fin x_in = (/1,2,3,4/) x_fin = (/0,0,0,0/) write(*,*)'x_in, x_fin before = ', x_in, x_fin call photon_trace(C_FLOAT(x_in),C_FLOAT(x_fin)) write(*,*)'x_in, x_fin after = ', x_in, x_fin end program main_dummy 

And this is a module with an interface:

 module raytracing Interface integer (C_INT) function photon_trace(x_init, x_final) & bind(C, name='photon_trace') use , intrinsic :: ISO_C_BINDING implicit none type (c_ptr), value :: x_init, x_final end function photon_trace end interface end module raytracing 

According to the guy who gave me the routine in C, x_init and x_final should be pointers (right?).

When I try to compile, it gives me an error in the argument list when I call photon_trace in the main program.

Any suggestions? I am using gcc 4.8

PS Does gcc 4.4 have the same features regarding iso_c_binding , or do I need to do something else to use it?

CHANGE AFTER VLADIMIR:

Thanks to Vladimir! I was calling a function because I saw it in this example https://stackoverflow.com/a/4646262

I made the modification you proposed, and now it compiles! The problem is that the C routine works with the address of the variables, not the variables themselves.

I put some print in the C routine:

 int photon_trace(double x_init[4], double x_final[4]) //*************************************************** { double r,m,t,phi; t = x_init[0]; r = x_init[1]; m = x_init[2]; phi = x_init[3]; printf("t0 %f\n", t); printf("r0 %f\n", r); printf("m0 %f\n", t); printf("phi0 %f\n", r); t=t+1.0; r=r+1.0; m=m+1.0; phi=phi+1.0; printf("t1 %f\n", t); printf("r1 %f\n", r); printf("m1 %f\n", t); printf("phi1 %f\n", r); x_final[0] = t; x_final[1] = r; x_final[2] = m; x_final[3] = phi; return 0; } 

as well as mainly:

 program main_dummy ! compile: gcc -c dummy_trace.c ! f95 raytracing.f90 main_dummy.f90 dummy_trace.o -o main use, intrinsic :: ISO_C_BINDING use raytracing implicit none !real(kind=8) :: x_in(4), x_fin(4) real(C_FLOAT), dimension(0:3) :: x_in, x_fin integer :: rt_ok x_in = (/1,2,3,4/) x_fin = (/0,0,0,0/) write(*,*)'x_in, x_fin before = ', x_in, x_fin rt_ok = photon_trace(x_in,x_fin) write(*,*)'return rt = ', rt_ok write(*,*)'x_in, x_fin after = ', x_in, x_fin end program main_dummy 

and what's on the screen:

 x_in, x_fin before = 1.00000000 2.00000000 3.00000000 4.00000000 0.00000000 0.00000000 0.00000000 0.00000000 t0 2.000000 r0 512.000123 m0 2.000000 phi0 512.000123 t1 3.000000 r1 513.000123 m1 3.000000 phi1 513.000123 return rt = 0 x_in, x_fin after = 1.00000000 2.00000000 3.00000000 4.00000000 1.00000000 2.12500000 3.00000000 4.00097656 

What's going on here?

Thank you very much for your precious help!

+2
source share
1 answer

Do not over complicate this. Don’t miss pointers, but pass arrays by reference

In addition, the function should be used in the expression, and not in the call statement.

 module raytracing Interface integer (C_INT) function photon_trace(x_init, x_final) & bind(C, name='photon_trace') use , intrinsic :: ISO_C_BINDING implicit none real(c_double) :: x_init(4), x_final(4) end function photon_trace end interface end module raytracing program main_dummy ! compile: f95 raytracing.f90 main_dummy.f90 dummy_trace.o -o main use, intrinsic :: ISO_C_BINDING use raytracing implicit none real(c_double), dimension(0:3) :: x_in, x_fin integer ie x_in = (/1,2,3,4/) x_fin = (/0,0,0,0/) write(*,*)'x_in, x_fin before = ', x_in, x_fin ie = photon_trace(x_in,x_fin) write(*,*)'x_in, x_fin after = ', x_in, x_fin end program main_dummy 

In C compatible procedures, Fortran passes variable pointers if you are not using value . This is called pass by reference.

 > gfortran ray.c ray.f90 > ./a.out x_in, x_fin before = 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000 x_in, x_fin after = 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 5.0000000000000000 

PS gcc 4.4 is very old, but theoretically he knows C interop stuff. Try it and you will see.

+4
source

Source: https://habr.com/ru/post/1239661/


All Articles