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

passing concatenated string to subroutine

jansson
Beginner
966 Views
Hello all Fortran experts, I have a subroutine calling another subroutine and want to pass a modified copy of a input string to the second subroutine. SUBROUTINE SUB1(STR1) CHARACTER*(*) STR1 CALL SUB2( TRIM(STR1)//' ;!' ) END SUBROUTINE SUB2(STR2) CHARACTER*(*) STR2 STR2(1:4)="test" END Could I do like this without breaking any Fortran rules? This seems much easier than to explicitly allocate a new string, copy and modify the string in SUB1 before passing it to SUB2. I do not want changes made to STR2 to affect STR1. Will STR2 endup on the stack or does it depend? Regards, Magnus
0 Kudos
1 Solution
Steven_L_Intel1
Employee
966 Views

The code you posted is not legal Fortran. You're passing an expression, and it is not allowed to modify the associated dummy argument. In practice, what our compiler (and most others) do is create a temporary with the expression value and pass the temporary, so the modification will not affect the caller. 

If you want the called routine to modify the dummy argument without affecting the caller, even if just a plain variable is passed, then Arjen's advice to add the VALUE attribute is correct. Note that this then requires an explicit interface for the called routine to be visible to the caller.

View solution in original post

0 Kudos
7 Replies
Arjen_Markus
Honored Contributor I
966 Views

If you pass a concatenated string, it is not a variable or a part of a variable, but an expression. But as I read your question more carefully, you are not interested in changing the value of the actual argument.

What you are after is the VALUE attribute. That will turn the dummy argument into something that gets its value from the actual argument but is no longer connected to it:

subroutine sub2( str2 )

character(len=*), value :: str2


 

0 Kudos
jansson
Beginner
966 Views

Thanks for your answer Markus,

True, I do not want to change the value of STR1 even if the value of STR2 is changed while STR2 is "parsed" in SUB2.

The solution you give is more elegant, but I am uncomfortable using it since the rest of our code in this file are in F77.
The solution I described works in all tests I did so far and are more F77 as I understand it. But I might wave missed the important test case that make this construct fail. That is why I ask if it break any Fortran rule. :) But I might allso have missed the point in your answer.

Where can I read more about "passing" expressions to subroutines in Fortran?

Cheers,
Magnus

0 Kudos
Arjen_Markus
Honored Contributor I
965 Views

As long as you are using a compiler that supports Fortran 2003 (that is when the attribute was introduced), it does not really matter whether the rest of the code uses the FORTRAN 77 standard.

As for reading about expressions, I can only refer to the standard, though a number of threads in this forum or in comp.lang.fortran might be more immediately useful. Usually the compiler will warn you about the wrong use, if you give it enough information. One such thing is to declare the INTENT for dummy arguments and making the interface explicit, for instance by putting the routines in a module:

subroutine sub2( str2 )

   character(len=*), intent(out) :: str2

   ...

end subroutine sub2

would make it impossible to pass an expression like trim(str2) // '1' - the actual argument must be modifiable

0 Kudos
jimdempseyatthecove
Honored Contributor III
966 Views

>>would make it impossible to pass an expression like trim(str2) // '1' - the actual argument must be modifiable

Only when the interface is known.

F77 style did not use interfaces. If the subroutine is not in a module (and used) .OR. does not have an interface (in procedure or module), then the subroutine declared interface is unknown to the caller.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
967 Views

The code you posted is not legal Fortran. You're passing an expression, and it is not allowed to modify the associated dummy argument. In practice, what our compiler (and most others) do is create a temporary with the expression value and pass the temporary, so the modification will not affect the caller. 

If you want the called routine to modify the dummy argument without affecting the caller, even if just a plain variable is passed, then Arjen's advice to add the VALUE attribute is correct. Note that this then requires an explicit interface for the called routine to be visible to the caller.

0 Kudos
jansson
Beginner
966 Views
Thank you all for your enlighting answers. Since my first solution is not legal Fortan and I want to avoid hard to find craches in the future I go for a temporary automatic object instead. The VALUE attribute would have been nice but Interfaces or modules would cause me more work to do. SUBROUTINE SUB1(STR1) CHARACTER( len=* ) STR1 CHARACTER( len=len(STR1) ) TMP TMP=TRIM(STR1)//' ;!' CALL SUB2( TMP ) END Any other ideas? Thanks for the nice help, this is a great Forum! Cheers, Magnus
0 Kudos
jimdempseyatthecove
Honored Contributor III
966 Views

You may want to consider

CHARACTER( len=len(STR1)+2) TMP
! +2 in the event that STR1 has fewer than 2 trailing blanks

If you want to future-proof your program, then you need to module-ize your program. In the process, you may uncover some bugs.

Jim Dempsey

0 Kudos
Reply