- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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 messageTestF2003_C.f90:61.29:Call cfunc_intarray(c_loc(i_array),n)1Error: Argument 'i_array' to 'c_loc' at (1) must be an associated scalar POINTERwhile ifort works fine. Which one is right?Thanks,Blaise
Link Copied
4 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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 Mod1Use, Intrinsic :: iso_c_bindingEnd Module Mod1Module Mod2Use, Intrinsic :: iso_c_bindingInterfaceSubroutine cfunc_int(i) bind(c,name='printint')Use Mod1Integer(c_int), value :: iEnd SubroutineEnd InterfaceInterfaceSubroutine cfunc_intptr(i) bind(c,name='printintptr')Use Mod1Type(C_Ptr), value :: iEnd SubroutineEnd InterfaceInterfaceSubroutine cfunc_intarray(i,n) bind(c,name='printintarray')Use Mod1Type(C_Ptr), value :: iInteger(c_int), value :: nEnd SubroutineEnd InterfaceInterfaceSubroutine cfunc_chararray(s,n) bind(c,name='printconstcharlist')Use Mod1Type(C_Ptr), dimension(1) :: sInteger(kind=c_int), value :: nEnd Subroutine cfunc_chararrayEnd InterfaceEnd Module Mod2Program mainUse Mod2implicit noneInteger(kind=c_int) :: i, nInteger(kind=c_int), target :: iptrInteger(Kind=C_int), Dimension(:), Pointer :: ip_arrayInteger(Kind=C_int), Dimension(:), Allocatable, Target :: it_arrayCharacter(len=99,kind=C_char), dimension(:), Pointer :: sp_arrayType(C_Ptr), Dimension(:),Pointer :: S_Ptri = 12Call cfunc_int(i)iptr=13Call cfunc_intptr(c_loc(iptr))n = 5Allocate(ip_array(n))Allocate(it_array(n))Do i = 1, nip_array(i) = iEnd Doit_array = ip_arrayCall cfunc_intarray(c_loc(it_array),n)DeAllocate(ip_array)DeAllocate(it_array)Allocate(sp_array(n))Allocate(S_Ptr(n))Do i = 1, nWrite(sp_array(i), 100) i,C_NULL_CHAREnd Do100 format('*** sp_array /',I5,'/ ***',A)Do i = 1, nS_Ptr(i) = C_loc(sp_array(i))End DoCall cfunc_chararray(S_Ptr, n)DeAllocate(sp_array)DeAllocate(S_Ptr)Write(*,*) 'All done!'End Program main
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Use (*) instead of (1).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Of course!
Thanks a lot
Blaise

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page