Passing an inline string to a subroutine call where the parameter has a specific length gives unexpected results

I found that this code behaves 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 depends on the compiler.

I see that the problem is that I jump through the procedure with len=* for the string argument, which is then passed to the routine with the specified length for the string argument.

What happens exactly under the hood, and where does the standard describe this behavior? Should I abstain from the given length for the arguments of the characteristic arguments, since this behavior can occur at any time without warning?

+4
source share
3 answers

I think your code is not up to the mark. Section 12.4.1.1 standard Fortran 95 states:

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

+5
source

The problem is that bar requires a string of length 50 (see character(len=LCHARS), intent(in) :: str ), while the string you pass in has a length of 6. Compilation with

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

causes an error

forrtl: strong (408): fort: (18): The character variable "STR" has a length of 50, which is longer than the actual variable of length 6

To my knowledge , all Fortran arguments are passed by reference . Behind the scenes, the bar function gets a pointer to the beginning of the string str and an additional parameter whose value is equal to the length of the string. Thus, bar will take up 50 characters of memory starting at the beginning of str and print it to the screen. Since the line you are passing is only 6 characters long, the remaining 44 characters will be in the next bit of memory after "foobar", which will differ at run time or depending on the compiler you use.

+3
source

The passage of the argument depends on the compiler if the requirements of the standard are met, but, as a rule, the argument of the argument CHARACTER (len = *) will have an interface similar to

void foo (char * s, int len)

and in the implementation of the foo procedure, the hidden len argument is used as the length of the string. OTOH, for the argument CHARACTER (len = somevalue), the hidden len argument is either ignored or not passed at all, and the procedure code assumes that somevalue is the correct string length.

As you saw, you should never use anything other than LEN = * unless you really know what you are doing, and you can quote the chapter and verse from the standard to explain why.

+2
source

Source: https://habr.com/ru/post/1391435/


All Articles