Question: How do I get the 28 back to Fortran?
main.f90:
program test
use play_dice_game
use iso_c_binding, only : c_ptr, c_f_pointer, c_null_ptr
type(c_ptr) :: test_ptr
integer, pointer :: ftest_ptr
integer result
test_ptr = c_null_ptr
result = roll_dice(test_ptr)
call c_f_pointer(test_ptr, ftest_ptr)
write(*,*) 'C test pointer is ',test_ptr
write(*,*) 'Fortran test pointer is ',ftest_ptr
end program test
play_dice_game.f90:
module play_dice_game
use, intrinsic :: iso_c_binding, only: c_int, c_ptr
interface
function roll_dice(test_p) bind(c, name="roll_dice_")
import :: c_int, c_ptr
implicit none
type(c_ptr), intent(out) :: test_p
integer(c_int) :: roll_dice
end function
end interface
end module play_dice_game
test.c:
#include <stdio.h>
#include <stdlib.h>
int roll_dice_(int *test) {
if (!*test)
{
printf ("Creating storage for test\n");
test = malloc(sizeof(int));
*test = 28;
printf ("variable test is set to %d\n\n",*test);
}
else
{
printf ("test is not null\n");
}
return 0;
}
Compile and Run Program:
gcc -g -c test.c -o test.o
gfortran -g -c play_dice_game.f90 -o play_dice_game.o
gfortran -g -c main.f90 -o main.o
gfortran -g main.o test.o -o main.exe -lgfortran
./main.exe
Output:
Creating storage for test variable test is set to 28
C test pointer is 0 Fortran test pointer is 0
I tried using c_f_pointer without success. But, if I define in the C file a struct with an int and reference it in the Fortran file I can get the "28" in Fortran. I'd like something simple.
In C:
struct myint {
int int_tmp;
};
int roll_dice_(struct myint **test)
...
*test = malloc(sizeof(**test));
...
(*test)->int_tmp = 28;
In Fortran:
type(myint), pointer :: intvar
call c_f_pointer(myint_ptr, intvar)
write(*,*) 'my int = ', intvar%int_tmp
CodePudding user response:
I have no idea how fortran works, but your C function has a problem. You allocate memory and then loose the pointer to that memory.
I suggest you take an int **
in roll_dice_
instead to be able to return a pointer to the allocated memory. Example:
#include <stdio.h>
#include <stdlib.h>
int roll_dice_(int **test) {
if(!test) {
puts("test is null");
return 0; // 0 for fail
}
if(!*test) {
printf("Creating storage for test\n");
*test = malloc(sizeof **test);
} else {
printf("*test is not null\n");
}
**test = 28;
printf("variable test is set to %d\n\n", **test);
return 1; // 1 for success
}
Possible output:
Creating storage for test
variable test is set to 28
C test pointer is 11640096
Fortran test pointer is 28
Note: The program will leak the malloc
ed bytes unless you add a free
too.
From PierU's comment:
Fortran passes arguments by address: when you call
roll_dice(test_ptr)
, this is not the content oftest_ptr
that is passed, but its address. That is, in terms of C a pointer to a pointer. Besides, for code correctness,test_p
should beintent(inout)
in your interface.