Hello,
I am writing some Fortran bindings to a C library that I wrote, which itself builds upon HDF5 to create a file format for dynamics simulations. In particular, I have functions that produce an array of strings with the following prototype (see below for an example implementation):
int c_array_processing(my_type *a, int n, char **result);
Here my_type
is a struct
holding info about the file I am reading, n
is the number of elements in the array I want, and results
is the array created by the function. The C function is written so that it should be used in the following way:
my_type *a = ...;
int n = 2; // for instance
char *values[n];
int res = c_array_processing(a, n, values);
I have tested it, and it works as expected. Now I have the written the following Fortran interface:
interface
integer(kind=c_int) function f90_array_processing(a, n, result) bind(C, name="c_array_processing")
use iso_c_binding, only: c_int, c_ptr
integer(kind=c_int), value, intent(in) :: a
integer(kind=c_int), value, intent(in) :: n
type(c_ptr), intent(out) :: result
end function f90_array_processing
end interface
and my problem is that the value of n
changes after the call to the function…
This minimal example shows the problems I have, with a C function c_array_processing
that does roughly what the function in the real library is doing:
lib.c
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int c_array_processing(int *a, int n, char **test) {
printf("n in C (start) is %d\n", n);
printf("n in C (before loop) is %d\n", n);
for (int i=0; i<n; i++) {
test[i] = malloc( sizeof(char *) * 255);
test[i][0] = '\0';
strncat(test[i], "Test", strlen("Test")+1);
}
printf("n in C (after loop) is %d\n", n);
return 0;
}
int c_no_array(int *a, int n) {
printf("n in C is %d\n", n);
return 0;
}
prog.f90
:
program test
use iso_c_binding, only: c_int, c_ptr
implicit none
interface
integer(kind=c_int) function f90_array_processing(a, n, test) bind(C, name="c_array_processing")
use iso_c_binding, only: c_int, c_ptr
integer(kind=c_int), intent(in) :: a
integer(kind=c_int), value, intent(in) :: n
type(c_ptr), intent(out) :: test
end function f90_array_processing
end interface
interface
integer(kind=c_int) function f90_no_array(a, n) bind(C, name="c_no_array")
use iso_c_binding, only: c_int, c_ptr
integer(kind=c_int), intent(in) :: a
integer(kind=c_int), value, intent(in) :: n
end function f90_no_array
end interface
print '(A)', 'Printing return value of functions'
print '(A)', '=================================='
call test_routine_print_res()
print *, ''
print '(A)', 'Not printing return value of functions'
print '(A)', '======================================'
call test_routine_no_res()
contains
subroutine test_routine_print_res()
integer(kind=c_int) :: a, res
integer(kind=c_int) :: n
type(c_ptr) :: test
a = 10
n = 2
print '(A,I0)', 'F90 START: n = ', n
print '(A)', ' * Calling f90_array_processing'
res = f90_array_processing(a, n, test)
print '(A)', ' * After call:'
print '(A,I0)', ' res = ', res
print '(A,I0)', ' n = ', n
print '(A)', ' * Calling f90_no_array'
res = f90_no_array(a, n)
print '(A)', ' * After call:'
print '(A,I0)', ' res = ', res
print '(A,I0)', ' n = ', n
end subroutine test_routine_print_res
subroutine test_routine_no_res()
integer(kind=c_int) :: a, res, res2
integer(kind=c_int) :: n
type(c_ptr) :: test
a = 10
n = 2
print '(A,I0)', 'F90 START: n = ', n
print '(A)', ' * Calling f90_array_processing'
res = f90_array_processing(a, n, test)
print '(A)', ' * After call:'
print '(A,I0)', ' n = ', n
print '(A)', ' * Calling f90_no_array'
res = f90_no_array(a, n)
print '(A)', ' * After call:'
print '(A,I0)', ' n = ', n
end subroutine test_routine_no_res
end program test
Makefile
:
SRC_f90=prog.f90
SRC_C=lib.c
OBJ=prog.o lib.o
all: test_f90
test_f90: c_lib f90_prog
gfortran -o $@ $(OBJ)
f90_prog: prog.f90
gfortran -c -O0 $<
c_lib: lib.c
gcc -c -O0 $<
clean:
find . -name "*.o" -delete
find . -name "*.mod" -delete
.PHONY: clean
Here are the results:
$ ./test_f90
Printing return value of functions
==================================
F90 START: n = 2
* Calling f90_array_processing
n in C (start) is 2
n in C (before loop) is 2
n in C (after loop) is 2
* After call:
res = 0
n = 2
* Calling f90_no_array
n in C is 2
* After call:
res = 0
n = 2
Not printing return value of functions
======================================
F90 START: n = 2
* Calling f90_array_processing
n in C (start) is 2
n in C (before loop) is 2
n in C (after loop) is 2
* After call:
n = 25745
* Calling f90_no_array
n in C is 25745
* After call:
n = 25745
As you can see, in the second case, the value of n
is changing, and I cannot see why. I suppose that must have something to do with the string array allocations in the C function, but I am a bit lost here…
I have full control over the C library, so I can modify it to have a better interface !
Thanks a lot for your help !