There are three ways of passing data between a program and a subprogram: (i) the argument list of the subprogram, (ii) the return value of the subprogram if it is a function and (iii) global variables. The concept of arguments and return values of subprograms are common to many programming languages including FORTRAN and C. The ways in which global variables are handled are rather different. In FORTRAN there are common blocks whereas in C there are external variables or structures. Each of these will be considered in turn.
This is the main method for passing data between a calling program and the called subprogram. The calling program takes the actual arguments of the call to the subprogram, constructs an argument list and then passes execution to that routine. The subprogram then uses the values in the argument list to access the actual arguments. It may pass data back to the calling program by modifying the data in some or all of the arguments. As far as passing arguments between a program and a subprogram is concerned, the principal difference between FORTRAN and C is the method used for passing the arguments.
Note that the above paragraph refers to modifying arguments. On all the machines we support, the actual contents of the argument list is never modified. What may be modified is the contents of the location pointed to by an element of the argument list. This is not to say that other computers would not modify the argument list itself.
There are three commonly used methods for passing subprogram arguments: call by value, call by reference and call by descriptor. Call by value passes the actual value of the argument to the called routine, call by reference passes a pointer to the value of the argument (i.e. the address of the argument) and call by descriptor passes a pointer to a structure describing the argument.
Although these are the basic methods of passing arguments, a particular type of argument may be passed by a combination of these. For example, some compilers use a combination of call by reference and call by value to pass character arguments. What is common is that all arguments are passed by exchanging data values. It is how those values are to be interpreted that gives rise to the different mechanisms.
The FORTRAN standard does not specify how arguments should be passed to subprograms and indeed different compilers for different machines do use different methods. It is most usual for numeric data types to be passed by reference since the subprogram may modify the value of the argument. This is most easily achieved by passing a pointer to the storage location containing the data value, rather than a copy of the value itself. On the other hand, the C standard explicitly states that values cannot be returned to the calling routine directly through arguments and so call by value is most commonly used. It is worth recalling that the argument list of a routine is simply a sequence of computer words. If these are a list of addresses of data values then everything is simple. However, suppose that an array was passed by value. This would mean that the compiler would have to arrange for a copy of the entire array to be placed in the argument list that was passed to the called subprogram. Consequently, arrays are invariably passed by reference or by descriptor, never by value.
It may seem tedious to have to think about the actual mechanisms that a compiler uses to pass data between routines when all you want to do is to get on with your programming. However, understanding this is the key to mixed language programming. Fortunately the facilities described in More on Calling C from FORTRAN (Section 5) and More on Calling FORTRAN from C (Section 8) hide much of this from the programmer.
The second mechanism for passing data between routines is the return value of a function. FORTRAN
makes a distinction between subprograms that return a value (functions) and those that do not
(subroutines), whereas C does not. All C subprograms are functions that return a value (even
the main program), although that value may be void
. Since it is simply a value that is
being returned, the mechanisms for returning scalar numeric values tend to be just that – a
value is returned. However, things get more complicated in the case of functions returning
things like character variables. This will be discussed further in appendix A on machine
dependencies.
Different languages can have very different ways of dealing with variables that are not local to a
particular routine, but have a more global scope. FORTRAN has common blocks for global data that
are accessed by particular routines. The data values in a common block can be accessed by different
names in different routines, although this is generally considered bad practice. C functions can
access global data by using variables that are not declared in a particular routine, but have
a scope of all the routines contained in the source file in which the global variables are
defined. If the same variable is needed across several source files, then it can be declared as
extern
.
Although these two mechanisms are very different in principle, in practice, computer manufacturers tend to implement them in a way such that it is possible to share global data between routines that have been written in different languages. The details of how this is done are given in the appendix about specific machines. However, there is an indirect way of accessing FORTRAN common blocks from C that is also worth considering. The FORTRAN routine that calls the C function can pass as an argument, the first element of the common block. As long as FORTRAN passes this argument by reference, then the C function can use this address to access all of the other elements of the common block. The elements of the common block must be stored contiguously. Whether this method, or the use of the F77 macros (described in Section 5.8), achieve a greater degree of portability in this respect is not known at present. On account of these potential portability problems, you should avoid passing global data between routines written in different languages, whenever possible.