Fortran How does Fortran know the Inputs and Outputs of Subroutines

AI Thread Summary
Fortran determines the inputs and outputs of subroutines primarily through a call-by-reference mechanism, where the addresses of variables are passed. Variables used in a subroutine must be defined in both the main program and the subroutine, but they can have different names. A subroutine can modify input variables, and if they are passed by reference, those changes will reflect in the main program. Additionally, a subroutine cannot access variables defined in the main program unless they are explicitly passed as arguments or shared through COMMON blocks, which can lead to unintended side effects. Understanding these principles is crucial for effectively working with Fortran code and avoiding errors during porting or debugging.
  • #51
jbriggs444 said:
The standard disagrees.
Where?

Fortran 90 standard said:
2.3.4 Execution sequence

Execution of an executable program begins with the first executable construct of the main program. The execution of a main program or subprogram involves execution of the executable constructs within its scoping unit. When a procedure is invoked, execution begins with the first executable construct appearing after the invoked entry point. With the following exceptions, the effect of execution is as if the executable constructs are executed in the order in which they appear in the main program or subprogram until a STOP, RETURN, or END statement is executed. The exceptions are:

  1. (1) Execution of a branching statement (8.2) changes the execution sequence. These statements explicitly specify a new starting place for the execution sequence.
  2. (2) IF constructs, CASE constructs, and DO constructs contain an internal statement structure and execution of these constructs involves implicit (i.e., automatic) internal branching. See Section 8 for the detailed semantics of each of these constructs.
  3. (3) Alternate return and END=, ERR=, and EOR= specifiers may result in a branch.
Internal subprograms may precede the END statement of a main program or a subprogram. The execution sequence excludes all such definitions.
(emphasis added)
 
Technology news on Phys.org
  • #54
I also stand corrected. Thanks!
 
  • #55
Here's how C deals with a very similar situation.
C:
// Test.c
#include <stdio.h>
void func(int *, int *, int *);

int main(void)
{
   int y = 1;
   func(&y, &y, &y);
   printf("y = %d", y);
   return 0;
}

void func(int * a, int * b, int * c)
{
   *a = 2;
   *b = 3;
   *c = 4;
}
Output: y = 4
 
  • #56
ecastro said:
I have another question regarding this. The subroutine 'atmref' calls the 'opsol' subroutine with three of its outputs have the same name (the first call of the subroutine, for example), 'rolutd'. In the code of the 'opsol' subroutine, these three outputs are three different variables, so which one of these will have be considered 'rolutd'?
I agree with @jbriggs444 that the standard doesn't allow it. But my fortran compiler (Intel visual fortran 2011) let's it pass and indeed, OSPOL (not opsol) is called twice as you describe. The effect -- IF the code to write to the rolut(m,l) is executed -- is as @DrClaude describes and the lookup table would get completely wrong values. a disastrous bug. However, in the example we use,
Fortran:
C Look up table generation
      do m=1,mu
      do l=1,nfilut(m)
      phimul=filut(m,l)*pi/180.
      rolut(m,l)=rolut(m,l)+delta0s*i3(m)*cos(is*(phimul+pi))
      rolutq(m,l)=rolutq(m,l)+delta0s*q3(m)*cos(is*(phimul+pi))
      rolutu(m,l)=rolutu(m,l)+delta0s*u3(m)*sin(is*(phimul+pi))
      enddo
      enddo
C end of look up table generation
nfilut(m) is all zeroes in all calls from atmref: it looks as if the reference table is not used for this set of inputs. Pretty inefficient (or a bug!) :rolleyes:

I can't oversee what the first two calls to ospol from atmref are supposed to do and if they should be the same as the third one, or instead need dummy arrays (of the proper size) as the last two arguments.
 
  • #57
@ecastro : my advice is to get into contact with the authors. If they published the stuff in 2015 that means there are still users and perhaps also developers working with/on this stuff. If I were one of them, I would be extremely grateful for this kind of detailed feedback. And perhaps they will also be interested in what you are trying to make !
 
  • #58
Thank you all for your help. I also wanted to contact the authors, but I wanted to confirm if it is a programming error or if I understand how Fortran works. I just found out that 'rolutd' is not used in 'atmref' (like a dummy output), that is maybe why the compiler let it pass?
 
  • #59
ecastro said:
Thank you all for your help. I also wanted to contact the authors, but I wanted to confirm if it is a programming error or if I understand how Fortran works. I just found out that 'rolutd' is not used in 'atmref' (like a dummy output), that is maybe why the compiler let it pass?
Compilers do not detect all standards violations. Their job is simpler than that -- to take compliant programs and generate object code that will produce compliant results.

In the development environment that I am familiar with, the Fortran compiler would (or could) do separate compilation of each subroutine. When compiling 'atmref', the compiler would have knowledge of where and how 'atmref' will be called. So the compiler would not generate a compile time error message for 'atmref'. When compiling the caller of 'atmref', the compiler would have no knowledge of the inner workings of 'atmref'. So the compiler would not generate a compile time error message when compiling the caller.

It would be possible for the compiler to build in run time checks to detect and flag attempts to modify aliased dummy parameters. But the standard does not require that this be done. The standard does not specify the required behavior when running non-compliant code.

However, it is also plausible that your re-examination of the code is correct, that there is no attempt to modify an aliased dummy variable and that this particular standards violation does not exist in the code.
 
  • Like
Likes ecastro
  • #60
I would just like to chip into contest the frequently asserted claim that "Fortran is a language where calls are intrinsically by-reference", by "referring" to a blog post by Steve Lionel a.k.a. Doctor Fortran (formerly?) of Intel. https://software.intel.com/en-us/blogs/2009/03/31/doctor-fortran-in-ive-come-here-for-an-argument

On a fundamental level, argument association is pretty simple. Although most people would tell you that Fortran uses "pass by reference", meaning that the address of the actual argument is used for the dummy argument, that's not quite true. The standard says that argument association is "usually similar to call by reference" and then adds "The actual mechanism by which this happens is determined by the processor." [Fortran 2003 Note 12.22]

There are some cases where what actually gets passed is not the original argument. The most common case for this is when a non-contiguous array pointer or a array slice is passed to an argument for which the compiler does not see an explicit interface specifying that the corresponding dummy argument is an assumed-shape array. Because the called routine is expecting a contiguous array, the compiler needs to make a copy of the actual argument, pass the copy, and then copy back any changes. The compiler can warn you about this at run-time if you use the option /check:arg_temp_created (Windows) or -check arg_temp_created (Linux/Mac OS). The compiler will generate a run-time test to see if the argument is actually contiguous and skip the copy if it is.

He goes on to give some more examples then emphasises the importance of explicitly declaring INTENT, but I think the point is clear.
 

Similar threads

Replies
3
Views
2K
Replies
25
Views
3K
Replies
8
Views
4K
Replies
5
Views
8K
Replies
10
Views
10K
Replies
5
Views
3K
Back
Top