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

Implicit length character array and bind(c) subroutine

Allen_Barnett
Beginner
1,251 Views

We recently updated to IFORT 15.0.2.179. A few of the regression tests for our code system now fail. The basic pattern is calling a function written in C with a slice of a two-dimensional character array; the compiler is not passing a pointer to the correct word in the character array. Here is a reduced example; we declare an interface to the C routine and iterate over the rows of a character array, passing the first column to the C function:

module r
  interface
     subroutine cprint ( leng, chars ) bind (c)
       use, intrinsic :: iso_c_binding, only : c_int, c_char
       integer(kind=c_int) :: leng
       character(kind=c_char,len=1) :: chars( leng )
     end subroutine cprint
  end interface
end module r

subroutine b ( leng, chars )
  use r
  integer :: leng, i
  character(len=*) :: chars( leng, 2 )
  do i = 1, 2
     call cprint( leng, chars(:,i) )
  end do
end subroutine b

program a
  integer, parameter :: leng = 23
  integer :: i
  character(len=1) :: chars( leng, 2 )
  character(len=leng) :: buffer
  buffer = 'ABCDEFGHIJ'
  do i = 1, leng
     chars(i,1) = buffer(i:i)
  end do
  buffer = '1234567890'
  do i = 1, leng
     chars(i,2) = buffer(i:i)
  end do
  call b( leng, chars )
end program a

and the C++ subroutine:

#include <cstdio>
extern "C" void cprint ( const int* leng, const char* chars )
{
  for ( int i = 0; i < *leng; ++i ) {
    putc( chars, stdout );
  }
  putc( '\n', stdout );
  fflush( stdout );
}

I expect this to print:

ABCDEFGHIJ
1234567890

But instead I get:

ABCDEFGHIJ
ABCDEFGHIJ

If I look at the assembly code for subroutine b, it appears that the correct address for chars(:,i) is not being computed; it just uses the same address for each iteration.

Variations: If I replace character(len=*) with character(len=1) in subroutine b, the correct strings are printed by cprint. If I leave in (len=*) but call a Fortran print subroutine with the same arguments, the correct strings are printed.

I tried my example program with ifort 14.0.4.237 and it also prints the incorrect strings. But, our main program, which is lot larger, works correctly. Kind of odd.

Thanks,
Allen

0 Kudos
8 Replies
Andrew_Smith
Valued Contributor I
1,251 Views

Your example does not pass an array slice to C.

Did you mean to use:

call b( leng, chars(:,1) )

call b( leng, chars(:,2) )

0 Kudos
Allen_Barnett
Beginner
1,251 Views

Hmm. It's supposed to pass the 2D array to subroutine b and then a slice of that is passed on to the C function cprint.  Does it not do that?
Allen
 

0 Kudos
Steven_L_Intel1
Employee
1,251 Views

Interesting. Declaring "chars" in subroutine b as len=1 rather than len=* gives the correct behavior, even though they should be the same here. We'll take a look.

0 Kudos
Steven_L_Intel1
Employee
1,251 Views

I can go back to version 12.1 and still see the bad behavior. Which compiler version did you use where you got the results you like?

0 Kudos
Allen_Barnett
Beginner
1,251 Views

Our main code has had this idiom for a long time, probably since version 11, and it has always worked until 15.0.  The compiler has never complained.

We've been reading the Fortran standard and it probably is an error to use len=*, but it has worked as-is for a long time.

Thanks,
Allen

0 Kudos
Steven_L_Intel1
Employee
1,251 Views

No, it's not an error to use len=* - b is not a bind(c) routine. I escalated this as issue DPD200366425 - I tried all compilers back to 12.1 and got the same bad results. Very puzzling. Removing bind(c) from cprint (which is declared correctly) also corrects the behavior.

0 Kudos
Steven_L_Intel1
Employee
1,251 Views

This has been fixed for a release later this year.

0 Kudos
Allen_Barnett
Beginner
1,251 Views

Thanks!

0 Kudos
Reply