Fortran calling C: cannot fix mixed_str_len on Linux

Hi,

When both a pointer and string are passed from Fortran to C, the strlen argument occupies unexpected place on stack. On Windows, this is fixable by !dec$ attributes (or by -Miface option), but on Linux and Mac OS the order seems to be not under control.

Could you suggest a solution?
Removing the pointer from argument list helps, but this is not an option in my case.

Caller.f90:

program caller

  interface
     integer function ifoo(p,o,s)
       !dec$ attributes c :: ifoo
       !dec$ attributes reference :: ifoo
       integer, pointer :: p
       integer :: o
       character(*) :: s
     end function ifoo
  end interface

  integer, target :: n
  integer, pointer :: p
  character(123) :: s

  n = 519
  p => n
  s = "something"
  print *, "calling ifoo, expect ifoo( *:519, *:45, *:[some], 123 )"
  i = ifoo(p,45,s)
  print *,i,s
end program caller

ifoo.c:

#include <stdio.h>
int ifoo_(int **h, int *i, char *s, int len)
{
   printf("ifoo( %p:%d, %p:%d, %p:[%4.4s], %d )\n",
          h,**h,i,*i,s,s,len);
   fflush(0);
   return 0;
}

Using gcc+gfortran I have this output:

calling ifoo, expect ifoo( *:519, *:45, *:[some], *)
ifoo( 0x7fff73e21cc0:519, 0x400c54:45, 0x7fff73e21c40:[some], 123 )
0 something

With PGI C and Fortran 10.8 the output is this:

calling ifoo, expect ifoo( *:519, *:45, *:[some], 123 )
ifoo( 0xfff875f4:519, 0x8075f98:45, 0x807c038:[some], -494084 )
0
something

Thanks
Dima

Hi Dima,

The problem here is the pointer. We’re passing in a second hidden argument for the pointer descriptor that’s coming before the size of the character array. Do you really need the pointer? Why not use ISO_C_BINDING?

For example:

% cat Caller.f90 
program caller

  use iso_c_binding
  interface
     function ifoo(p,o,s) BIND(C)
       use iso_c_binding
       integer(C_INT) :: ifoo
       integer(C_INT) :: p
       integer(C_INT), value :: o
       character(*) :: s
     end function ifoo
  end interface

  integer :: n,i
  character(123) :: s

  n = 519
  s = "something"//char(0)
  print *, "calling ifoo, expect ifoo( *:519, *:45, *:[some], 123 )"
  i = ifoo(n,45,s)
  print *,i,s
end program caller 

% cat ifoo.c 
#include <stdio.h>
int ifoo(int *h, int i, char *s, int len)
{
   printf("ifoo( %p:%d, %p:%d, %p:[%4.4s], %d )\n",
          h,*h,&i,i,s,s,len);
   fflush(0);
   return 0;
} 

% pgcc -c ifoo.c
% pgf90 Caller.f90 ifoo.o
Caller.f90:
% a.out
 calling ifoo, expect ifoo( *:519, *:45, *:[some], 123 )
ifoo( 0x7fff505f4408:519, 0x7fff505f435c:45, 0x7fff505f4380:[some], 123 )
            0 
 something
  • Mat

Mat,

Thank you for suggestion. I have an issue with bind(c), however.
Many compilers other than PGI Fortran complaint or even trigger an error about passing character(*) to the function which is bind(c). De facto Fortran characters and C chars are interoperable in most cases, and it is the strlen that creates portabililty problem.

Thank you for explanation of the purpose of the hidden parameter that shifts strlen from the expected place. It should be possible to get rid of it by translating the fortran pointer to c_ptr and passing the c_ptr by reference (you see, I have to receive int** rather than int* in ifoo).

It would be nice, however, if PGI Fortran recognized !dec$ not only on Windows.

Thanks
Dima