whatyouhide
whatyouhide

Reputation: 16781

Fortran 'call' statement: what can it actually call?

I've inherited about 400 lines of very weirdly written Fortran 77 code, and I'm trying to analyze it step by step to make it clear in my mind.

Anyway, I have an header-like file (actually a .h, but the code in it is in fortran not C/C++) with JUST two statements in it, called getarg.h:

character*80 serie
integer ln

Then I have another fortran file (.f) called getserie.h which has this code inside it:

subroutine getserie(serie, ln)
include 'getarg.h'
call getarg(1, serie)
ln = index(serie, ' ') - 1
return
end

My question being: can I call an external file with just variables declarations in it? What's the effect of doing this?

Upvotes: 2

Views: 7089

Answers (3)

agentp
agentp

Reputation: 6989

as noted the only thing weird here is a questionable choice of the name of the include file. (both the .h extension and the irrelevant use of an intrinsic symbol name). (yes i know getarg is not pedantically standard f77, but an extension)

Putting variable declarations in an include file is (/was) common practice to ensure consistent declarations among program units. Undoubtedly that file is also 'included' in the calling program, and ensures that your string is declared with the same length everywhere.

That said in this example it is most certainly unnecessary. You can declare the string an assumed length, so put in place of the include:

character serie*(*)
integer ln

as well as normal declarations in the main program and get rid of the include file clutter.

(now someone will tell me about some compiler in the early part of the last century not supporting assumed length string declarations)..

Upvotes: 0

No, you can call only subroutines. This means subprograms designated as subroutine. However the definition of the subroutine does not have to be in your source file. It just have to be supplied at link time.

The getarg subroutine is probably an intrinsic subroutine of your compiler which gets the command line arguments. This means that the compiler provides the code of the subroutine to the linker automatically.

The file getarg.h is not called in any way. Its content is just copied directly to the place of the include statement.

There are situations where you need to have an (explicit) interface of the called subroutine available, but in later Fortran versions, 90 and later. In these modern versions you normally place the subroutines and functions in modules, so that the compiler can check you are calling them correctly.

Upvotes: 6

Hristo Iliev
Hristo Iliev

Reputation: 74395

One peculiar feature of most FORTRAN implementations is that CALL can call almost any external symbol. Of course, only calling SUBROUTINEs makes sense. This is possible because of the well-known FORTRAN calling convention - all actual arguments are passed by address, i.e. all actually passed arguments to a subroutine are of equal type - they are all pointers. Even constants are passed by address - the address of the memory location which contains the value of the constant. This allows the compiler to generate calls to any subroutine without the need for an explicit prototype to be supplied. It just pushes all argument pointers onto the stack (on platforms with stack-based calling convention) or loads them into the corresponding registers (on platforms with register calling convention) and emits an assembly call instruction to the address of the symbol, used as the subroutine name in the CALL statement. If such symbol exists at link time, the linker would produce an executable, otherwise it will complain about an unresolved symbol reference and no executable would be produced.

The same is also true for function calls. The only feature the compiler uses to tell a function call from an array indexing operation is that (non-intrinsic) functions are declared as EXTERNAL. The special EXTERNAL designation is necessary since the syntax for calling a function and for accessing an element of an array is the same. There are also special predefined functions, called intrinsic functions, which are internally recognised by the compiler (e.g. SIN). There are also intrinsic subroutines, but most of them are just library subroutines.

So whenever you encounter a CALL foo(...) statement and you don't know what foo is, you should consult your compiler's manual to see if an intrinsic by this name exists. If not, it is probably defined somewhere in the code - look for SUBROUTINE foo. If not, it should be an exported subroutine from an external library, linked into the program, or just a syntax error.

This all is highly error prone, since one can easily supply an actual argument of an entirely different type than the one that the subroutine expects, or one can even supply a different number of actual arugments and the compiler would still happily compile the code. Of course, such program usually crashes when run or produces meaningless results. That's why special programs like flint were developed in order to check the source code as a whole for problems that the compiler is unable to detect (e.g. arguments type mismatch, wrong number of actual arguments, etc.) Fortran 90 fixes this by introducing interfaces. Interfaces are mandatory in certain situations, but can be used in general to provide compile-time arguments checking.

Upvotes: 1

Related Questions