I have the following test function:
#include <stdlib.h>
#include <stdio.h>
void print_string(char *text);
void print_string(char *text) {
printf("---\n%s\n---\n", text);
}
And the following module which encapsulates the call with a Fortran subroutine using iso c bindings:
module test_c_lib
use iso_c_binding
implicit none
contains
subroutine test(text)
use iso_c_binding
character,intent(in) :: text(:)
! Interface to C function
interface
subroutine c_print_string(t) bind(C, name="print_string")
import
character(kind=c_char) :: t(:)
end subroutine
end interface
! Call C function
print *,"AAAAA"
print *,text
print *,"AAAAA"
call c_print_string(text // C_NULL_CHAR)
end subroutine
end module
The way to define the subroutine in Fortran using ISO C BINDINGS is extracted from this documentation link. I further encapsulate it a bit as f2py
does not support iso c bindings.
I compile everything via makefile
:
$ cat makefile
f_mod.so: f_mod.f90 c_lib.o
f2py -c f_mod.f90 c_lib.o -m f_mod
c_lib.o: c_lib.c
gcc -c -fpic c_lib.c -o c_lib.o
It compiles but:
150 | call c_print_string(text // C_NULL_CHAR)
| 1
Warning: Character length mismatch (2/1) between actual argument and assumed-shape dummy argument 't' at (1) [-Wargument-mismatch]
import fmod; f_mod.test_c_lib.test("Foo")
: AAAAA
Foo
AAAAA
---
8v$
---
So f2py
is working but when passing text // C_NULL_CHAR
as parameter it does not seem to work as I get garbage from the C function output.
You have two mistakes:
//
is treated elementallyTo make the character dummy argument interoperable with the char *
C parameter, t
should be an assumed size array:
character(kind=c_char) :: t(*) ! Assumed size, not assumed shape
You can also use the CFI_cdesc_t
C type to have t
an assumed shape array, or an assumed length scalar, but that's a lot more advanced.
Even making t
assumed size, you don't have a working procedure, because of the next problem: the elemental nature of //
.
As text
is an (assumed shape) array the concatenation text // C_NULL_CHAR
is done elementally, giving the length-2 array1 with each element of text
concatenated with the C null char. The C function then sees input looking like [text(1), C_NULL_CHAR, text(2), C_NULL_CHAR, ...]
.
To have a length-1 character array with C_NULL_CHAR
appended, you need to use an array constructor:
call c_print_string([text,C_NULL_CHAR])
1 That the argument is of length-2 is the reason for the warning about a "character length mismatch".