Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a string inline to a subroutine call, where the parameter has defined length, gives unexpected results

I found this code to behave unexpectedly

module testmodule
   integer, parameter :: LCHARS = 50
contains
   subroutine init()
      call foobar("foobar")
   end subroutine

   subroutine foobar(s)
      character(len=*), intent(in) :: s
      call bar(s)
   end subroutine

   subroutine bar(str)
      character(len=LCHARS), intent(in)  :: str

      print *, str
   end subroutine
end module

program foo
   use testmodule
   call init()
end program

This code prints garbage which is compiler dependent.

I see the problem being the fact that I am jumping through a routine with len=* for a string argument, which is then passed to a routine with specified length for the string argument.

What's going on exactly under the hood, and where in the standard is this behavior described? Should I refrain from having specified length for character routine arguments, since this behavior may happen at any time without warning?

like image 258
Stefano Borini Avatar asked Dec 28 '22 07:12

Stefano Borini


2 Answers

I think your code is non-conforming. Section 12.4.1.1 of the Fortran 95 standard states:

12.4.1.1 Actual arguments associated with dummy data objects
[...]
If a scalar dummy argument is of type default character, the length len of the dummy argument shall be less than or equal to the length of the actual argument. The dummy argument becomes associated with the leftmost len characters of the actual argument.

like image 154
eriktous Avatar answered May 17 '23 12:05

eriktous


The problem is that bar requires a string of length 50 (cf. character(len=LCHARS), intent(in) :: str), whereas the string you are passing it is only of length 6. Compiling this with

ifort -Warn all,nodec,interfaces,declarations -gen_interfaces -check all -std test.f90

produces the error

forrtl: severe (408): fort: (18): Dummy character variable 'STR' has length 50 which is greater then actual variable length 6

As far as know all Fortran arguments are passed by reference. Behind the scenes, what the function bar gets is a pointer to the start of the string str and an extra parameter whose value is the length of the string. So bar will take 50 characters worth of memory, starting at the beginning of str, and print that to screen. Since the string that you pass is only 6 characters long, the remaining 44 characters will be whatever is in the next bit of memory after "foobar", which will differ at run time or depending on the compiler you use.

like image 40
Chris Avatar answered May 17 '23 10:05

Chris