- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Stumbled upon an odd situation last week.
It is likely that the complier setting on the RedHat5 were using "-save" and the RedHat6 I was porting to was not.
The code looks something like this:
PROGRAM SunShine IMPLICIT NONE !... Declarations are in here CALL XX(Date_n_Time, Sun_Position, SunShine) !... File writing code is in here END PROGRAM SunShine SUBROUTINE XX(Time, Sun, SunShine) IMPLICIT NONE TYPE Position REAL(KIND=8) :: Lat REAL(KIND=8) :: Lon REAL(KIND=8) :: Alt END TYPE Position TYPE(Position), DIMENSION(360*181) :: Place_as_a_Vector !... Additional Declarations are in here... LOGICAL(KIND=4) DIMENSION(360,181), INTENT( OUT) :: SunShine TYPE(POSITION) , INTENT(IN ) :: Sun REAL(KIND=8) , INTENT(IN ) :: Date_n_Time LOGICAL(KIND=4) :: Init_Me = .TRUE. IF(Init_Me) THEN K = 0 DO I = 1, 360 DO J = -90, 90 K = K + 1 Place_as_a_Vector(K)%Lat = FLOAT(J) Place_as_a_Vector(K)%Lon = FLOAT(I) Place_as_a_Vector(K)%Alt = 0.0 ENDDO ENDDO Init_Me = .FALSE. ENDIF !... Some more code here... RETURN END SUBROUTINE XX
Without either ",SAVE" on "Card 15's" "Place_as_a_Vector" declaration line, or "Place_as_a_Vector = 0" then the variable is not saved.
Are there some strategies for catching these?
"-check uninit" is one, but I am not sure if any other -warn gives insight that can help in identifying where I should be paying attention, especially when I cam coming into a subroutine or function after the first time.
There are /QSave etc, but I probably need to make sure that the code is more bullet proof, and there are quite a few lines of code.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Note that your code, as shown, has a non-sequence, non-bind(c) type defined local to an external subroutine, that is the type of of one of a non-optional argument. There is no way that the external subroutine can be called in a conforming program.
Apart from the runtime -check options, the inspector tool might be useful for catching this sort of error.
I think having any saved state "hidden" in variables local to procedures is far from ideal.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
IanH wrote:
Note that your code, as shown, has a non-sequence, non-bind(c) type defined local to an external subroutine, that is the type of of one of a non-optional argument. There is no way that the external subroutine can be called in a conforming program..
I am not sure what you mean by "non-sequence, non-bind(c) type defined local to an external subroutine", and I am poking in the code from memory as we do not have decent internet connectivity at work. I am passing in a time and a position and getting out an array of logicals.
Sticking in the ,SAVE fixed the problem, but being able to find others without beard-stroking each routine would be useful. The code now looks like:
TYPE(Position), DIMENSION(360*181) , SAVE :: Place_as_a_Vector
IanH wrote:
Apart from the runtime -check options, the inspector tool might be useful for catching this sort of error.
I think I agree, but I do not believe that we have inspector installed,.. only the ifort and icc. Or maybe I need to figure out how to get to inspector on Linux??
IanH wrote:
I think having any saved state "hidden" in variables local to procedures is far from ideal.
The calling routine or main routine does not need insight into the array called "Places_as_an_Array", and I only want to initialise this once. So the variable to save the initialisation also seems to be not required to be resident in the caller.
What would you call ideal?
Having this array in a module? And then the module present in the caller and the callee?
I may need to balance "ideal" with also being somewhat being readable by F77 users. In this case a module would work, but I am upon to ideas.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If the code was written to work with an older (especially mainframe) compiler, pinching one's nose and using the -save option is the simplest solution. Microsoft FPS and Compaq/Digital CVF adopted the convention of SAVE for all variables by default.
However, you can look for blocks of code with a tell-tale sign, such as the variable Init_Me of type Logical and assigned the initial value .TRUE., followed by a block of code surrounded by IF (Init_Me) THEN...END IF. All local variables to which values are assigned in the loop probably need the attribute SAVE.
Secondly, look for local variables that are used in an expression with no previous statements that define them. These may need SAVE as well, but it can be difficult to decide when the code contains lots of jumps and conditional statements.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
holmz wrote:
I am not sure what you mean by "non-sequence, non-bind(c) type defined local to an external subroutine", and I am poking in the code from memory as we do not have decent internet connectivity at work.
I suspect your actual code is different then... my point was that the type Position is defined locally in the subroutine (its external nature is a red herring). That type doesn't have BIND(C) or SEQUENCE, so that definition is unique - even if the same fragment of Fortran source for the type appeared elsewhere it would define a different type. One of the dummy arguments of that subroutine is of that local type, and that dummy argument is not optional, hence any call to the subroutine must include an actual argument of that type. But because the type definition is strictly local, it is impossible to declare or create an object that could be such an actual argument, hence it is impossible to call the procedure in a conforming manner.
It is a question of programming style, rather than a hard guideline, but I very much prefer procedures to be procedural. With limited exceptions I do not use SAVE'd variables in procedures at all. If there is state to be passed from procedure invocation to procedure invocation, then I carry that state across in a dummy argument. This simplifies the situation when code inevitably evolves to require multiple instances of that state to be extant at one time, or for the state to be reset or similar. Note though, that I am talking about my stance for new code, rather than limited maintenance of old code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
mecej4 wrote:
However, you can look for blocks of code with a tell-tale sign, such as the variable Init_Me of type Logical and assigned the initial value .TRUE., followed by a block of code surrounded by IF (Init_Me) THEN...END IF. All local variables to which values are assigned in the loop probably need the attribute SAVE.
Well I cannot blame the "Init_Me" and "_as_a_vector" on anyone else... ;) Those clearly are my doing.
It does not appear that I can make use of compiler checks and warning to catch these.
I think I will also have to look at BIND(C)...
IanH wrote:
Quote:
holmz wrote:I am not sure what you mean by "non-sequence, non-bind(c) type defined local to an external subroutine", and I am poking in the code from memory as we do not have decent internet connectivity at work.
I suspect your actual code is different then... my point was that the type Position is defined locally in the subroutine (its external nature is a red herring). That type doesn't have BIND(C) or SEQUENCE, so that definition is unique - even if the same fragment of Fortran source for the type appeared elsewhere it would define a different type. One of the dummy arguments of that subroutine is of that local type, and that dummy argument is not optional, hence any call to the subroutine must include an actual argument of that type. But because the type definition is strictly local, it is impossible to declare or create an object that could be such an actual argument, hence it is impossible to call the procedure in a conforming manner.
The card #3 was meant to indicate that the same structure/type was in the main routine.
And that record is actually in a module that the main and the subroutine use. But poking it in by hand from recollection is always fraught with memory/brain leaks.
IanH wrote:
It is a question of programming style, rather than a hard guideline, but I very much prefer procedures to be procedural. With limited exceptions I do not use SAVE'd variables in procedures at all. If there is state to be passed from procedure invocation to procedure invocation, then I carry that state across in a dummy argument. This simplifies the situation when code inevitably evolves to require multiple instances of that state to be extant at one time, or for the state to be reset or similar. Note though, that I am talking about my stance for new code, rather than limited maintenance of old code.
Ah... Yes...
Something to keep in mind... This code is not threaded or using any implicit parallelism (yet), but I will ponder the implication of this.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page