Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29252 Discussions

ISO_C_BINDINGS: how to pass array of strings

bbourdin
Beginner
1,408 Views
Hi,
I am trying to understand better the C interoperability in fortran 2003. I have been able to write functions that pass scalar and arrays as arguments, but can;t figure out how to pass an array of string. More precisely, say that I have a C function
#undef __FUNCT__
#define __FUNCT__ "printconstcharlist"
void printconstcharlist(const char *const*list,int n) {
int i;
printf("\\nThis is %s\\n",__FUNCT__);
for (i=1; i
printf(" s[%i]=%s\\n",i,list);
}
}
What should the matching interface and calling sequence should be so that I can call it from fortran?
I am attaching a small example implementing the C functions and illustrating the interface in simpler cases.
Also, gfortran won;t compile this example and gives the following error message
TestF2003_C.f90:61.29:
Call cfunc_intarray(c_loc(i_array),n)
1
Error: Argument 'i_array' to 'c_loc' at (1) must be an associated scalar POINTER
while ifort works fine. Which one is right?
Thanks,
Blaise
0 Kudos
4 Replies
Steven_L_Intel1
Employee
1,408 Views
I am not a C expert, but I will comment that not all C constructs can be represented in Fortran using the Fortran 2003 C interoperability features.

Regarding the diagnostic you get from gfortran - an error at this point is appropriate but the one that gfortran gives is not what I would choose, since there are other possibilities for this argument.

C_LOC has several requirements for the arguments. Contrary to what Tim says in his private reply, the standard does not require that a compiler diagnose failure to meet these requirements, though certainly it is preferable if it does.

In your case, i_array fails the test of being either an interoperable type or a non-polymorphic scalar with no length attribute. A CHARACTER variable is interoperable only if it is length 1. It also fails because it is a pointer but is not scalar (as gfortran notes).

In the case of "an array of strings", the way to represent this in Fortran would be an array of type C_PTR to which you assign values using C_LOC.
0 Kudos
bbourdin
Beginner
1,408 Views
Dear Steve and Timothy,
Thanks for your help.
I followed your advice and was able to pass scalar by address and value, and arrays of scalar. ABout arrays of strings, I followed Steve's advice and got the following code, but I am not quite sure that it is legal (I am worried about the dimension(1) in the cfunc_chararray interface). It compiles without warning and runs fine under ifort 11.1 and gfortran 4.6.0 under Mac OS 10.6.
Would you mind having a look at the attached program and comment?
Thanks,
Blaise
Module Mod1
Use, Intrinsic :: iso_c_binding
End Module Mod1
Module Mod2
Use, Intrinsic :: iso_c_binding
Interface
Subroutine cfunc_int(i) bind(c,name='printint')
Use Mod1
Integer(c_int), value :: i
End Subroutine
End Interface
Interface
Subroutine cfunc_intptr(i) bind(c,name='printintptr')
Use Mod1
Type(C_Ptr), value :: i
End Subroutine
End Interface
Interface
Subroutine cfunc_intarray(i,n) bind(c,name='printintarray')
Use Mod1
Type(C_Ptr), value :: i
Integer(c_int), value :: n
End Subroutine
End Interface
Interface
Subroutine cfunc_chararray(s,n) bind(c,name='printconstcharlist')
Use Mod1
Type(C_Ptr), dimension(1) :: s
Integer(kind=c_int), value :: n
End Subroutine cfunc_chararray
End Interface
End Module Mod2
Program main
Use Mod2
implicit none
Integer(kind=c_int) :: i, n
Integer(kind=c_int), target :: iptr
Integer(Kind=C_int), Dimension(:), Pointer :: ip_array
Integer(Kind=C_int), Dimension(:), Allocatable, Target :: it_array
Character(len=99,kind=C_char), dimension(:), Pointer :: sp_array
Type(C_Ptr), Dimension(:),Pointer :: S_Ptr
i = 12
Call cfunc_int(i)
iptr=13
Call cfunc_intptr(c_loc(iptr))
n = 5
Allocate(ip_array(n))
Allocate(it_array(n))
Do i = 1, n
ip_array(i) = i
End Do
it_array = ip_array
Call cfunc_intarray(c_loc(it_array),n)
DeAllocate(ip_array)
DeAllocate(it_array)
Allocate(sp_array(n))
Allocate(S_Ptr(n))
Do i = 1, n
Write(sp_array(i), 100) i,C_NULL_CHAR
End Do
100 format('*** sp_array /',I5,'/ ***',A)
Do i = 1, n
S_Ptr(i) = C_loc(sp_array(i))
End Do
Call cfunc_chararray(S_Ptr, n)
DeAllocate(sp_array)
DeAllocate(S_Ptr)
Write(*,*) 'All done!'
End Program main
0 Kudos
Steven_L_Intel1
Employee
1,408 Views
Use (*) instead of (1).
0 Kudos
bbourdin
Beginner
1,408 Views
Of course!
Thanks a lot
Blaise
0 Kudos
Reply