Compaq Fortran
User Manual for
OpenVMS Alpha Systems


Previous Contents Index


Chapter 10
Using Compaq Fortran in the Common Language Environment

This chapter provides information on the following topics:

Compaq Fortran provides you with a variety of mechanisms for gaining access to procedures and system services external to your Compaq Fortran programs. By including CALL statements or function references in your source program, you can use procedures such as mathematical functions, OpenVMS system services, and routines written in such languages as Compaq Fortran 77 and Compaq C.

The Compaq Fortran compiler operates within the OpenVMS common language environment, which defines certain calling procedures and guidelines. These guidelines allow you to use Compaq Fortran to call OpenVMS system or library routines and routines written in different languages (usually called mixed-language programming).

This chapter provides information on the OpenVMS procedure-calling standard and how to access OpenVMS system services.

For More Information:

About calling and using the RMS (Record Management Services) system services, see Chapter 11.

10.1 Compaq Fortran Procedures and Argument Passing

The bounds of the main program are usually defined by using PROGRAM and END or END PROGRAM statements. Within the main program, you can define entities related to calling a function or subroutine, including modules and interface blocks.

A function or subroutine is considered a subprogram. A subprogram can accept one or more data values passed from the calling routine; the values are called arguments.

There are two types of arguments:

The following methods define the interface between procedures:

For More Information:

On the Compaq Fortran language, including statement functions and defined assignment statements not described in this manual, see the Compaq Fortran Language Reference Manual.

10.1.1 Explicit and Implicit Interfaces

An explicit interface occurs when the properties of the subprogram interface are known within the scope of the function or subroutine reference. For example, the function reference or CALL statement occurs at a point where the function or subroutine definition is known through host or use association. Intrinsic procedures also have an explicit interface.

An implicit interface occurs when the properties of the subprogram interface are not known within the scope of the function or subroutine reference. In this case, the procedure data interface is unknown to the compiler. For example, external routines (EXTERNAL statement) that have not been defined in an interface block have an implicit interface.

In most cases, you can use a procedure interface block to make an implicit interface an explicit one. An explicit interface provides the following advantages over an implicit interface:

For More Information:

On Compaq Fortran array descriptors, see Section 10.1.7.

10.1.2 Types of Compaq Fortran Subprograms

There are three major types of subprograms:

10.1.3 Using Procedure Interface Blocks

Procedure interface blocks allow you to specify an explicit interface for a subprogram as well as to define generic procedure names. This section limits discussion to those interface blocks used to provide an explicit subprogram interface. For complete information on interface blocks, see the Compaq Fortran Language Reference Manual.

The components of a procedure interface block follow:

For an example of a module that contains a procedure interface block, see Section 1.3.

10.1.4 Passing Arguments and Function Return Values

Compaq Fortran uses the same argument-passing conventions as Compaq Fortran 77 on OpenVMS Alpha systems for non-pointer scalar variables and explicit-shape and assumed-size arrays.

When calling Compaq Fortran subprograms, be aware that Compaq Fortran expects to receive arguments the same way it passes them.

The main points about argument passing and function return values are as follows:

The arguments passed from a calling routine must match the dummy arguments declared in the called function or subroutine (or other procedure), as follows:

For More Information:

10.1.5 Passing Arrays as Arguments

Certain arguments or function return values require the use of an explicit interface, including assumed-shape dummy arguments, pointer dummy arguments, and function return values that are arrays. This is discussed in the Compaq Fortran Language Reference Manual.

When passing arrays as arguments, the rank and the extents (number of elements in a dimension) should agree, so the arrays have the same shape and are conformable. If you use an assumed-shape array, the rank is specified and extents of the dummy array argument are taken from the actual array argument.

If the rank and extent (shape) do not agree, the arrays are not conformable. The assignment of elements from the actual array to the noncomformable (assumed-size or explicit-shape) dummy array is done by using array element sequence association.

Certain combinations of actual and dummy array arguments are disallowed.

For More Information:

10.1.6 Passing Pointers as Arguments

Previous sections have discussed the case where the actual and dummy arguments have neither the POINTER attribute nor the TARGET attribute.

The argument passing rules of like type, kind, and rank (for conformable arrays) or array element sequence association (for noncomformable arrays) apply when:

If you specify an actual argument of type POINTER and a dummy argument of type POINTER, the dummy argument receives the correct pointer value if you specify (in the code containing the actual argument) an appropriate explicit interface that defines the dummy argument with the POINTER attribute and follows certain rules.

However, if you specify an actual argument of type POINTER and do not specify an appropriate explicit interface (such as an interface block), it is passed as actual (target) data.

For More Information:

On using pointers and pointer arguments, see the Compaq Fortran Language Reference Manual.

10.1.7 Compaq Fortran Array Descriptor Format

When using an explicit interface (by association or procedure interface block), Compaq Fortran will generate a descriptor for the following types of dummy argument data structures:

To allow calling between Compaq Fortran 77 and Compaq Fortran, certain data structure arguments also supported by Compaq Fortran 77 do not use a descriptor, even when an appropriate explicit interface is provided. For example, since explicit-shape and assumed-size arrays are supported by both Compaq Fortran 77 and Compaq Fortran, an array descriptor is not used.

When calling between Compaq Fortran and a non-Fortran language (such as C), you can specify an appropriate explicit interface or use an implicit interface.

However, for cases where the called routine needs the information in the array descriptor, declare the routine with an assumed-shape argument and an explicit interface.

The array descriptor used by Compaq Fortran is the OpenVMS Noncontiguous Array Descriptor as described in the OpenVMS Calling Standard. In the DSC$B_AFLAGS byte, bit DSC$V_FL_UNALLOC specifies whether storage has or has not been set for this array. If this bit is set, the array has not yet been allocated.

For example, for 32-bit address access, consider the following array declaration:


   INTEGER,TARGET :: A(10,10) 
   INTEGER,POINTER :: P(:,:) 
   P => A(9:1:-2,1:9:3) 
   CALL F(P) 
   . 
   . 
   . 

The descriptor for actual argument P (using 32-bit addresses) would contain the following values:

For information about the Noncontiguous Array Descriptor when 64-bit addressing is requested (cDEC$ ATTRIBUTES ADDRESS64 directive), see the OpenVMS Calling Standard.

Note

1 For compatibility with older Compaq Fortran 77 OpenVMS VAX programs, character constant actual arguments (string literals) can be passed by reference if the Compaq Fortran program was compiled with the /BY_REF_CALL qualifier (see Section 2.3.9).

10.2 Argument-Passing Mechanisms and Built-In Functions

The OpenVMS procedure-calling standard defines three mechanisms by which arguments are passed to procedures:

By default, Compaq Fortran uses the reference and descriptor mechanisms to pass arguments, depending on each argument's data type:

When a Compaq Fortran program needs to call a routine written in a different language (or in some cases a Fortran 90 subprogram), there may be a need to use a form other the Compaq Fortran default mechanisms. For example, OpenVMS system services may require that certain numeric arguments be passed by immediate value instead of by reference.

For cases where you cannot use the default passing mechanisms, Compaq Fortran provides three built-in functions for passing arguments. It also provides a built-in function for computing addresses for use in argument lists. These built-in functions are as follows:

Except for the %LOC built-in function, which can be used in any arithmetic expression, these functions can appear only as unparenthesized arguments in argument lists. The three argument list built-in functions and %LOC built-in function are rarely used to call a procedure written in Compaq Fortran.

The use of these functions in system service calls is described in Section 10.7.4. The sections that follow describe their use in general.

Instead of using the Compaq Fortran built-in functions, you can use the cDEC$ ATTRIBUTES directive to change the Compaq Fortran default passing mechanisms (see Section 10.3.2).

10.2.1 Passing Arguments by Descriptor---%DESCR Function

The %DESCR function passes its argument by descriptor. It has the following form:

%DESCR(arg)

The argument generated by the compiler is the address of a descriptor of the argument (arg). The argument value can be any Fortran 90 expression. The argument value must not be a derived type, record name, record array name, or record array element. The compiler can generate OpenVMS descriptors for all Fortran data types.

In Compaq Fortran, the descriptor mechanism is the default for passing character arguments, Fortran 90 pointers, assumed-shape arrays, and deferred-shape arrays. This is because the subprogram may need to know the length or other information about the character, pointer, or array argument. Compaq Fortran always generates code to refer to character dummy arguments through the addresses in their character descriptors.

For More Information:

On Compaq Fortran array descriptors, see Section 10.1.7.

10.2.2 Passing Addresses---%LOC Function

The %LOC built-in function computes the address of a storage element as an INTEGER (KIND=8) (64-bit) value. With 64-bit addressing (cDEC$ ATTRIBUTE ADDRESS64 directive specified), all 64-bits are used. With 32-bit addressing (cDEC$ ATTRIBUTE ADDRESS64 directive omitted), only the lower 32 bits are used. You can then use this value in an arithmetic expression. It has the following form:

%LOC(arg)

The %LOC function is particularly useful for certain system services or non-Fortran procedures that may require argument data structures containing the addresses of storage elements. In such cases, the data structures should be declared volatile to protect them from possible optimizations.

For More Information:

10.2.3 Passing Arguments by Immediate Value---%VAL Function

The %VAL function passes the argument list entry as a 64-bit immediate value. It has the following form:

%VAL(arg)

The argument-list entry generated by the compiler is the value of the argument (arg). The argument value can be a constant, variable, array element, or expression of type INTEGER, LOGICAL, REAL (KIND=4), REAL (KIND=8), COMPLEX (KIND=4), or COMPLEX (KIND=8).

If a COMPLEX (KIND=4) or COMPLEX (KIND=8) argument is passed by value, two REAL arguments (one contains the real part; the other the imaginary part) are passed by immediate value. If a COMPLEX parameter to a routine is specified as received by value (or given the C attribute), two REAL parameters are received and stored in the real and imaginary parts of the COMPLEX parameter specified.

If the value is a byte, word, or longword, it is sign-extended to a quadword (eight bytes).

To produce a zero-extended value rather than a sign-extended value, use the ZEXT intrinsic function.

For More Information:

10.2.4 Passing Arguments by Reference---%REF Function

The %REF function passes the argument by reference. It has the following form:

%REF(arg)

The argument-list entry generated by the compiler will contain the address of the argument (arg). The argument value can be a record name, a procedure name, or a numeric or character expression, array, character array section, or array element. In Compaq Fortran, passing by reference is the default mechanism for numeric values, so the %REF call is usually not needed.

10.2.5 Examples of Argument Passing Built-in Functions

The following examples demonstrate the use of the argument list built-in functions.

  1. In this example, the first constant is passed by reference. The second constant is passed by immediate value:


      CALL SUB(2,%VAL(2)) 
    

  2. In this example, the first character variable is passed by character descriptor. The second character variable is passed by reference:


      CHARACTER(LEN=10) A,B 
      CALL SUB(A,%REF(B)) 
    

  3. In this example, the first array is passed by reference. The second array is passed by descriptor:


      INTEGER IARY(20), JARY(20) 
      CALL SUB(IARY,%DESCR(JARY)) 
    

10.3 Using the cDEC$ ALIAS and cDEC$ ATTRIBUTES Directives

This section provides reference information about the following directives:

10.3.1 The cDEC$ ALIAS Directive

Compaq Fortran now supports the cDEC$ ALIAS directive in the same manner as Compaq Fortran 77. Use this directive to specify that the external name of an external subprogram is different from the name by which the calling procedure references it.

The syntax is:

cDEC$ ALIAS internal-name, external-name

The internal-name is the name of the subprogram as used in the current program unit.

The external-name is either a quoted character constant (delimited by single quotation marks) or a symbolic name.

If external-name is a character constant, the value of that constant is used as the external name for the specified internal name. The character constant is used as it appears, with no modifications for case. The default for the Compaq Fortran compiler is to force the name into uppercase.

If external-name is a symbolic name, the symbolic name (in uppercase) is used as the external name for the specified internal name. Any other declaration of the specified symbolic name is ignored for the purposes of the ALIAS directive.

For example, in the following program (free source form):


  PROGRAM ALIAS_EXAMPLE 
  !DEC$ ALIAS ROUT1, 'ROUT1A' 
  !DEC$ ALIAS ROUT2, 'routine2_' 
  !DEC$ ALIAS ROUT3, rout3A 
        CALL ROUT1 
        CALL ROUT2 
        CALL ROUT3 
  END PROGRAM ALIAS_EXAMPLE 

The three calls are to external routines named ROUT1A, routine2_, and ROUT3A. Use single quotation marks (character constant) to specify a case-sensitive name.

This feature can be useful when porting code to systems where different routine naming conventions are in use. By adding or removing the cDEC$ ALIAS directive, you can specify an alternate routine name without recoding the application.

10.3.2 The cDEC$ ATTRIBUTES Directive

Use the cDEC$ ATTRIBUTES directive to specify properties for data objects and procedures. These properties let you specify how data is passed and the rules for invoking procedures. The cDEC$ ATTRIBUTES directive is intended to simplify mixed-language calls with Compaq Fortran routines written in C or Assembler.

The cDEC$ ATTRIBUTES directive takes the following form:


 cDEC$ ATTRIBUTES att [,att]... :: object [,object]... 

In this form:

c
Is the letter or character (c, C, *, !) that introduces the directive (see Compaq Fortran Language Reference Manual. )

att
Is one of the keywords listed in the Compaq Fortran Language Reference Manual. For example, C, ALIAS, REFERENCE, VALUE, EXTERN, VARYING, and ADDRESS64

object
Is the name of a data object used as an argument or procedure. Only one object is allowed when using the C and ALIAS properties.

The Compaq Fortran Language Reference Manual explains the valid combinations of properties with the various types of objects.

The ATTRIBUTES properties are described in the following sections:

10.3.2.1 C Property

The C property provides a convenient way for Compaq Fortran to interact with routines written in C.

When applied to a subprogram, the C property defines the subprogram as having a specific set of calling conventions.

The C property affects how arguments are passed, as described in Table 10-1.

Table 10-1 C Property and Argument Passing
Argument Variable Type Fortran Default C Property Specified for Routine
Scalar (includes derived types) Passed by reference Passed by value (large derived type variables may be passed by reference)
Scalar, with VALUE specified Passed by value Passed by value
Scalar, with REFERENCE specified Passed by reference Passed by reference
String Passed by character descriptor Passes the first character of the string, padded to a full integer
String, with VALUE specified Error Passes the first character of the string, padded to a full integer
String, with REFERENCE specified Passed by reference Passed by reference
Arrays, including pointers to arrays Always passed by reference Always passed by reference

If C is specified for a subprogram, arguments (except for arrays and characters) are passed by value. Subprograms using standard Fortran conventions pass arguments by reference.

Character arguments are passed as follows:

Example 10-1 shows Compaq Fortran code that calls the C function pnst by using the cDEC$ ATTRIBUTES C directive and C language passing conventions.

Example 10-1 Calling C Functions and Passing Integer Arguments

! Using !DEC$ ATTRIBUTES to pass argument to C. File: pass_int_cdec.f90 
 
interface 
   subroutine pnst(i) 
     !DEC$ ATTRIBUTES C :: pnst 
     integer i 
   end subroutine 
end interface 
 
  integer :: i 
  i = 99 
  call pnst(i)             ! pass by value 
  print *,"99==",i 
end 

Example 10-2 shows the C function called pnst that is called by the example program shown in Example 10-1

Example 10-2 Calling C Functions and Passing Integer Arguments

/* get integer by value from Fortran. File: pass_int_cdec_c.c */ 
 
void pnst(int i) { 
    printf("99==%d\n",i); 
        i = 100; 
} 

The files (shown in Example 10-1 and Example 10-2) might be compiled, linked, and run as follows:


$ CC PASS_INT_CDEC_C.C
$ FORTRAN PASS_INT_CDEC.F90
$ LINK/EXECUTABLE=PASS_CDEC PASS_INT_CDEC, PASS_INT_CDEC_C
$ RUN PASS_CDEC
99==99 
99==          99

10.3.2.2 ALIAS Property

You can specify the ALIAS property as cDEC$ ALIAS or as cDEC$ ATTRIBUTES ALIAS; they are equivalent, except that using cDEC$ ALIAS allows symbol names (see Section 10.3.1).

The ALIAS property allows you to specify that the external name of an external subprogram is different from the name by which the calling procedure references it (see Section 10.3.1).

10.3.2.3 REFERENCE and VALUE Properties

The following cDEC$ ATTRIBUTES properties specify how a dummy argument is to be passed:

Character values, substrings, and arrays cannot be passed by value. When REFERENCE is specified for a character argument, the string is passed with no descriptor.

VALUE is the default if the C property is specified in the subprogram definition (for scalar data only).

Consider the following free-form example, which passes an integer by value:


  interface 
    subroutine foo (a) 
     !DEC$ ATTRIBUTES value :: a 
        integer a 
    end subroutine foo 
  end interface 

This subroutine can be invoked from Compaq Fortran using the name foo:


   integer i 
   i = 1 
   call foo(i) 
 
   end program 

This is the actual subroutine code:


    subroutine foo (i) 
     !DEC$ ATTRIBUTES value :: i 
        integer i 
        i = i + 1 
        . 
        . 
    end subroutine foo 

10.3.2.4 EXTERN and VARYING Properties

The EXTERN property specifies that a variable is allocated in another source file. EXTERN can be used in global variable declarations, but it must not be applied to dummy arguments.

You must use EXTERN when accessing variables declared in other languages.

The VARYING directive allows a variable number of calling arguments. If VARYING is specified, the C property must also be specified.

When using the VARYING directive, either the first argument must be a number indicating how many arguments to process, or the last argument must be a special marker (such as -1 ) indicating it is the final argument. The sequence of the arguments, and types and kinds, must be compatible with the called procedure.

For More Information:

See the Compaq Fortran Language Reference Manual.

10.3.2.5 ADDRESS64 Property

Specifies that the object has a 64-bit address. This property can be specified for any variable or dummy argument, including ALLOCATABLE and deferred-shape arrays. However, variables with this property cannot be data-initialized.

It can also be specified for COMMON blocks or for variables in a COMMON block. If specified for a COMMON block variable, the COMMON block implicitly has the ADDRESS64 property.

ADDRESS64 is not compatible with the AUTOMATIC attribute.

For More Information:

10.4 OpenVMS Procedure-Calling Standard

Programs compiled by the Compaq Fortran compiler conform to the standard defined for OpenVMS Alpha procedure calls (see the OpenVMS Programming Interfaces: Calling a System Routine and OpenVMS Calling Standard). This standard prescribes how registers and the system-maintained call stack can be used, how function values are returned, how arguments are passed, and how procedures receive and return control.

When writing routines that can be called from Compaq Fortran programs, you should give special consideration to the argument list descriptions in Section 10.4.3.

10.4.1 Register and Stack Usage

The Alpha architecture provides 32 general purpose integer registers (R0-R31) and 32 floating-point registers (F0-F31), each 64 bits in length. The OpenVMS Programming Interfaces: Calling a System Routine defines the use of these registers, as listed in Table 10-2.

Table 10-2 OpenVMS Alpha Register Usage
Register Use
R0 Function value return registers; also see F0, F1
R1 Conventional scratch register
R2-R15 Conventional saved registers
R16-R21 Argument registers (one register per argument, additional arguments are placed on the stack)
R22-R24 Conventional scratch registers
R25 Argument information (AI); contains argument count and argument type
R26 Return address (RA) register
R27 Procedure value (PV) register
R28 Volatile scratch register
R29 Frame pointer (FP)
R30 Stack pointer (SP)
R31 Read As Zero/Sink (RZ) register
PC Program counter (PC), a special register that addresses the instruction stream, which is not accessible as an integer register
F0, F1 Function value return registers (F1 is used for the imaginary part of COMPLEX)
F2-F9 Conventional saved registers
F10-F15 Conventional scratch registers
F16-F21 Argument registers (one per argument, additional arguments are placed on the stack)
F22-F30 Conventional scratch registers
F31 Read As Zero/Sink (RZ) register

A stack is defined as a LIFO (last-in/first-out) temporary storage area that the system allocates for every user process.

Each time you call a routine, the system places information on the stack in the form of procedure context structures, as described in OpenVMS Calling Standard.

10.4.2 Return Values of Procedures

A procedure is a Compaq Fortran subprogram that performs one or more computations for other programs. Procedures can be either functions or subroutines. Both functions and subroutines can return values by storing them in variables specified in the argument list or in common blocks.

A function, unlike a subroutine, can also return a value to the calling program by assigning the value to the function's name. The method that function procedures use to return values depends on the data type of the value, as summarized in Table 10-3.

Table 10-3 Function Return Values
Data Type Return Method
  • Logical
  • Integer
R0
REAL (KIND=4) F0
REAL (KIND=8) F0
REAL (KIND=16) F0 and F1
COMPLEX (KIND=4)
(COMPLEX*8)
F0 (real part), F1 (imaginary part)
COMPLEX (KIND=8)
(COMPLEX*16)
F0 (real part), F1 (imaginary part)
COMPLEX (KIND=16)
(COMPLEX*32)
In addition to the arguments, an entry is added to the beginning of the argument list. This additional entry contains the address of the character string descriptor. At run time, before the call, the calling program allocates enough storage to contain the result and places the storage address in the descriptor.
Character In addition to the arguments, an entry is added to the beginning of the argument list. This additional entry contains the address of the character string descriptor. At run time, before the call, the calling program allocates enough storage to contain the result and places the storage address in the descriptor.
Pointers R0 contains the address of the array descriptor (see Section 10.1.6).
Assumed-shape arrays,
Deferred-shape arrays
R0 contains the address of the array descriptor (see Section 10.1.5).

For More Information:

10.4.3 Argument Lists

Use an argument list to pass information to a routine and receive results.

The OpenVMS Calling Standard defines an argument list as an argument item sequence, consisting of the first six arguments occupying six integer and six floating-point registers (R16-R21 and F16-F21), with additional arguments placed on the stack. The argument information is contained in R25 (AI register). The stack pointer is contained in R30. For more details on argument lists, see the OpenVMS Calling Standard.

Memory for Compaq Fortran argument lists and for OpenVMS Alpha descriptors is allocated dynamically on the stack.

OpenVMS Alpha descriptors are generated from the use of the %DESCR function or by passing CHARACTER data, Fortran 90 pointers, and certain types of arrays (see Section 10.1.7).

Omitted arguments---for example, CALL X(A, ,B)---are represented by an argument passed by value that has a value of zero. This is a Compaq extension to the Fortran 90 standard.

Fortran optional arguments (OPTIONAL attribute) are also represented by an argument passed by value that has a value of zero.

For More Information:

On using Fortran language standards to specify arguments, see the Compaq Fortran Language Reference Manual.

10.5 OpenVMS System Routines

System routines are OpenVMS routines that perform common tasks, such as finding the square root of a number or allocating virtual memory. You can call any system routine from your program, provided that Compaq Fortran supports the data structures required to call the routine (in a FORSYSDEF library module) or you define them yourself.

The system routines used most often are OpenVMS Run-Time Library routines and system services. System routines are documented in detail in the OpenVMS Run-Time Library Routines Volume and the OpenVMS System Services Reference Manual.

10.5.1 OpenVMS Run-Time Library Routines

The OpenVMS Run-Time Library provides commonly-used routines that perform a wide variety of functions. These routines are grouped according to the types of tasks they perform, and each group has a prefix that identifies those routines as members of a particular OpenVMS Run-Time Library facility. Table 10-4 lists all of the language-independent Run-Time Library facility prefixes and the types of tasks each facility performs.

Table 10-4 Run-Time Library Facilities
Facility Prefix Types of Tasks Performed
CVT$ Library routines that handle floating-point data conversion
DTK$ DECtalk routines that are used to control Compaq's DECtalk device
LIB$ Library routines that:
Obtain records from devices
Manipulate strings
Convert data types for I/O
Allocate resources
Obtain system information
Signal exceptions
Establish condition handlers
Enable detection of hardware exceptions
Process cross-reference data
MATH$ Mathematics routines that perform arithmetic, algebraic, and trigonometric calculations
OTS$ General-purpose routines that perform such tasks as data type conversions as part of a compiler's generated code
PPL$ Parallel processing routines that help you implement concurrent programs on single-CPU and multiprocessor systems
SMG$ Screen-management routines that are used in designing, composing, and keeping track of complex images on a video screen
STR$ String manipulation routines that perform such tasks as searching for substrings, concatenating strings, and prefixing and appending strings

10.5.2 OpenVMS System Services Routines

System services are system routines that perform a variety of tasks, such as controlling processes, communicating among processes, and coordinating I/O.

Unlike the OpenVMS Run-Time Library routines, which are divided into groups by facility, all system services share the same facility prefix (SYS$). However, these services are logically divided into groups that perform similar tasks. Table 10-5 describes these groups.

Table 10-5 System Services
Group Types of Tasks Performed
AST Allows processes to control the handling of ASTs
Change Mode Changes the access mode of particular routines
Condition Handling Designates condition handlers for special purposes
Event Flag Clears, sets, reads, and waits for event flags, and associates with event flag clusters
Input/Output Performs I/O directly, without going through OpenVMS RMS
Lock Management Enables processes to coordinate access to shareable system resources
Logical Names Provides methods of accessing and maintaining pairs of character string logical names and equivalence names
Memory Management Increases or decreases available virtual memory, controls paging and swapping, and creates and accesses shareable files of code or data
Process Control Creates, deletes, and controls execution of processes
Process Information Returns information about processes
Security Enhances the security of OpenVMS systems
Timer and Time Conversion Schedules events, and obtains and formats binary time values

10.6 Calling Routines---General Considerations

The basic steps for calling routines are the same whether you are calling a routine written in Compaq Fortran, a routine written in some other OpenVMS language, a system service, or a Compaq Fortran RTL routine.

To call a subroutine, use the CALL statement.

To call a function, reference the function name in an expression or as an argument in another routine call.

In any case, you must specify the name of the routine being called and all non-optional arguments required for that routine. Make sure the data types and passing mechanisms for the actual arguments you are passing coincide with those declared in the routine (see Table 10-6 for information on OpenVMS data types or OpenVMS Programming Interfaces: Calling a System Routine for data types needed for mixed language programming).

If you do not want to specify a value for a required parameter, you can pass a null argument by inserting a comma (,) as a placeholder in the argument list. If the routine requires any passing mechanism other than the default, you must specify the passing mechanism in the CALL statement or the function call.

Example 10-3 shows an example that uses the LIB$GET_VM RTL routine and the Compaq Fortran 77 POINTER statement to allocate memory for an array. This example uses Compaq extensions (POINTER statement and LIB$ routine) to allocate virtual memory. The routine name varies with the operating system (LIB$GET_VM on OpenVMS systems and malloc on UNIX systems).

Example 10-3 illustrates calling an OpenVMS RTL LIB$ routine.

Example 10-3 Use of LIB$GET_VM and POINTER

! Program accepts an integer and displays square root values 
 
  INTEGER (KIND=4) N 
  READ (5,*) N            ! Request typed integer value 
  CALL MAT(N) 
  END 
 
! Subroutine MAT uses the typed integer value to display the square 
! root values of numbers from 1 to N (the typed number) 
 
  SUBROUTINE MAT(N)       
  REAL I(1000)           ! Fixed 1000 dimension allows bounds checking 
  INTEGER SIZE,STATUS 
  POINTER (P,I)          ! Compaq Fortran 77 POINTER statement establishes 
                         ! P as the pointer and array variable I as the 
                         ! pointee. P will receive memory base address 
                         ! from LIB$GET_VM. 
 
  SIZE=SIZEOF(I(1)) * N  ! Array I contains values calculated in loop below. 
                         ! Intrinsic SIZEOF returns size of memory 
                         ! to allocate. 
 
  STATUS = LIB$GET_VM(SIZE,P)    ! Allocate memory 
  IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) 
 
  DO J=1,N 
     I(J) = SQRT(FLOAT(J))   ! Intrinsic FLOAT converts integer to REAL. 
  ENDDO 
  TYPE *, (I(J),J=1,N)       ! Display calculated values 
 
  STATUS = LIB$FREE_VM(SIZE,P)   ! Deallocate memory 
  IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) 
 
  END SUBROUTINE MAT 

The following commands show how to compile, link, and run the program and how it displays the square root of numbers from 1 to 4 during execution:


$ FORTRAN SQUARE_ROOT
$ LINK SQUARE_ROOT
$ RUN SQUARE_ROOT
4
   1.000000       1.414214       1.732051       2.000000 

The call to LIB$GET_VM as a function reference allocates memory and returns the starting address in variable P. The return status (variable STATUS) is tested to determine whether an error should be signaled using a subroutine call to LIB$SIGNAL, passing the value of the variable status (not its address) using the %VAL built-in function.

For More Information:

10.7 Calling OpenVMS System Services

You can invoke system services in a Compaq Fortran program with a function reference or a subroutine CALL statement that specifies the system service you want to use. To specify a system service, use the form:

SYS$service-name(arg,...,arg)

You pass arguments to the system services according to the requirements of the particular service you are calling; the service may require an immediate value, an address, the address of a descriptor, or the address of a data structure. Section 10.7.4 describes the Compaq Fortran syntax rules for each of these cases. See the OpenVMS System Services Reference Manual for a full definition of individual services.

The basic steps for calling system services are the same as those for calling any external routine. However, when calling system services (or Run-Time Library routines), additional information is often required. The sections that follow describe these requirements.

10.7.1 Obtaining Values for System Symbols

OpenVMS uses symbolic names to identify the following values or codes for system services:

The values chosen determine the specific action performed by the service.

The OpenVMS System Services Reference Manual describes the symbols that are used with each system service. The OpenVMS I/O User's Reference Manual describes the symbols that are used with I/O-related services.

The Compaq Fortran symbolic definition library FORSYSDEF contains Compaq Fortran source definitions for related groups of system symbols. Each related group of system symbols is stored in a separate text library module; for example, the library module $IODEF in FORSYSDEF contains PARAMETER statements that define the I/O function codes.

The library modules in FORSYSDEF correspond to the symbolic definition macros that OpenVMS MACRO programmers use to define system symbols. The library modules have the same names as the macros and contain Compaq Fortran source code, which is functionally equivalent to the MACRO source code. To determine whether you need to include other symbol definitions for the system service you want to use, refer to the documentation for that particular system service. If the documentation states that values are defined in a macro, you must include those symbol definitions in your program.

For example, the description for the flags argument in the SYS$MGBLSC (Map Global Section) system service states that "Symbolic names for the flag bits are defined by the $SECDEF macro." Therefore, when you call SYS$MGBLSC, you must include the definitions provided in the $SECDEF macro.

Library module $SYSSRVNAM in FORSYSDEF contains declarations for all system-service names. It contains the necessary INTEGER and EXTERNAL declarations for the system-service names. (The library module, once extracted from FORSYSDEF.TLB, also contains comments describing the arguments for each of the system services.) Also, library module $SSDEF contains system-service return status codes and is generally required whenever you access any of the services.

The library modules in FORSYSDEF contain definitions for constants, bit masks, and data structures. See Section 10.7.4.4 for a description of how to create data structure arguments in Compaq Fortran. Refer to Appendix D for a list of library modules that are in FORSYSDEF.

You can access the library modules in the FORSYSDEF library with the INCLUDE statement, using the following format:

INCLUDE '(library-module-name)'

The notation library-module-name represents the name of a library module contained in FORSYSDEF. The library FORSYSDEF is searched if the specified library module was not found in a previously searched library.

10.7.2 Calling System Services by Function Reference

In most cases, you should check the return status after calling a system service. Therefore, you should invoke system services by function reference rather than by issuing a call to a subroutine.

For example:


  INCLUDE '($SSDEF)' 
  INCLUDE '($SYSSRVNAM)' 
  INTEGER (KIND=2) CHANNEL 
     . 
     . 
     . 
  MBX_STATUS = SYS$CREMBX(,CHANNEL,,,,,'MAILBOX') 
  IF (MBX_STATUS .NE. SS$_NORMAL) GO TO 100 

In this example, the system service referenced is the Create Mailbox system service. An INTEGER (KIND=2) variable (CHANNEL) is declared to receive the channel number.

The function reference allows a return status value to be stored in the variable MBX_STATUS, which can then be checked for correct completion on return. If the function's return status is not SS$_NORMAL, failure is indicated and control is transferred to statement 100. At that point, some form of error processing can be undertaken.

You can also test the return status of a system service as a logical value. The status codes are defined so that when they are tested as logical values, successful codes have the value true and error codes have the value false. The last line in the preceding example could then be changed to the following:


   IF (.NOT. MBX_STATUS) GO TO 100 

Refer to the OpenVMS System Services Reference Manual for information concerning return status codes. The return status codes are included in the description of each system service.

10.7.3 Calling System Services as Subroutines

Subroutine calls to system services are made like other subroutine calls. For example, to call the Create Mailbox system service, issue a call to SYS$CREMBX, passing the appropriate arguments to it, as follows:


  CALL SYS$CREMBX(,CHANNEL,,,,,'MAILBOX') 

This call corresponds to the function reference described in Section 10.7.2. The main difference is that the status code returned by the system service is not tested. For this reason, you should avoid this method and use a function reference when calling system services whenever the service could fail for any reason.

10.7.4 Passing Arguments to System Services

The description of each system service in the OpenVMS System Services Reference Manual specifies the argument-passing method for each argument. Four methods are supported:

These methods are discussed separately in Section 10.7.4.1 through Section 10.7.4.4.

You can determine the arguments required by a system service from the service description in the OpenVMS System Services Reference Manual. Each system service description indicates the service name, the number of arguments required, and the positional dependency of each argument.

Table 10-6 lists the Compaq Fortran declarations that you can use to pass any of the standard OpenVMS data types as arguments. OpenVMS data types are defined in the OpenVMS Programming Interfaces: Calling a System Routine.

Instead of using record structure declarations for most standard OpenVMS data types, you can consider using derived-type structures if you use the SEQUENCE statement and are careful of alignment. However, RMS control block structures must be declared as record structures (STRUCTURE statement).

Table 10-6 Compaq Fortran Implementation of OpenVMS Data Types
OpenVMS Data Type Compaq Fortran Declaration
access_bit_names INTEGER (KIND=4) (2,32)
or
STRUCTURE /access_bit_names/
INTEGER (KIND=4) access_name_len
INTEGER (KIND=4) access_name_buf
END STRUCTURE !access_bit_names
RECORD /access_bit_names/ my_names(32)
access_mode BYTE or INTEGER (KIND=1)
address INTEGER (KIND=4)
address_range INTEGER (KIND=4) (2)
or
STRUCTURE /address_range/
INTEGER (KIND=4) low_address
INTEGER (KIND=4) high_address
END STRUCTURE
arg_list INTEGER (KIND=4)(n)
ast_procedure EXTERNAL
boolean LOGICAL (KIND=4)
byte_signed BYTE or INTEGER (KIND=1)
byte_unsigned BYTE 1 or INTEGER (KIND=1) 1
channel INTEGER (KIND=2)
char_string CHARACTER (LEN=n) 2
complex_number COMPLEX (KIND=4) 3
COMPLEX (KIND=8) 3
cond_value INTEGER (KIND=4)
context INTEGER (KIND=4)
date_time INTEGER (KIND=8)
device_name CHARACTER (LEN=n)
ef_cluster_name CHARACTER (LEN=n)
ef_number INTEGER (KIND=4)
exit_handler_block STRUCTURE /exhblock/
INTEGER (KIND=4) flink
INTEGER (KIND=4) exit_handler_addr
BYTE(3) %FILL
BYTE arg_count
INTEGER (KIND=4) cond_value
! .
! .(optional arguments ...
! . one argument per longword)
!
END STRUCTURE !cntrlblk

RECORD /exhblock/ myexh_block
fab INCLUDE '($FABDEF)'
RECORD /FABDEF/ myfab
file_protection INTEGER (KIND=4)
floating_point REAL (KIND=4) 3
REAL (KIND=8) 3
DOUBLE PRECISION 3
REAL (KIND=16) 3
function_code INTEGER (KIND=4)
identifier INTEGER (KIND=4)
invo_context_blk INCLUDE '($LIBICB)'
RECORD /INVO_CONTEXT_BLK/ invo_context_blk
invo_handle INTEGER (KIND=4)
io_status_block STRUCTURE /iosb/
INTEGER (KIND=2) iostat, ! return status
INTEGER (KIND=2) term_offset, ! Loc. of terminator
INTEGER (KIND=2) terminator, ! terminator value
INTEGER (KIND=2) term_size ! terminator size
END STRUCTURE

RECORD /iosb/ my_iosb
item_list_2 STRUCTURE /itmlst/
UNION
MAP
INTEGER (KIND=2) buflen,code
INTEGER (KIND=4) bufadr
END MAP
MAP
INTEGER (KIND=4) end_list /0/
END MAP
END UNION
END STRUCTURE !itmlst

RECORD /itmlst/ my_itmlst_2(n)
(Allocate n records, where n is the number item codes plus an extra element for the end-of-list item.)
item_list_3 STRUCTURE /itmlst/
UNION
MAP
INTEGER (KIND=2) buflen,code
INTEGER (KIND=4) bufadr,retlenadr
END MAP
MAP
INTEGER (KIND=4) end_list /0/
END MAP
END UNION
END STRUCTURE !itmlst

RECORD /itmlst/ my_itmlst_3(n)
(Allocate n records where n is the number item codes plus an extra element for the end-of-list item.)
item_list_pair STRUCTURE /itmlist_pair/
UNION
MAP
INTEGER (KIND=4) code
INTEGER (KIND=4) value
END MAP
MAP
INTEGER (KIND=4) end_list /0/
END MAP
END UNION
END STRUCTURE !itmlst_pair

RECORD /itmlst_pair/ my_itmlst_pair(n)
(Allocate n records where n is the number item codes plus an extra element for the end-of-list item.)
item_quota_list STRUCTURE /item_quota_list/
MAP
BYTE quota_name
INTEGER (KIND=4) quota_value
END MAP
MAP
BYTE end_quota_list
END MAP
END STRUCTURE !item_quota_list
lock_id INTEGER (KIND=4)
lock_status_block STRUCTURE/lksb/
INTEGER (KIND=2) cond_value
INTEGER (KIND=2) unused
INTEGER (KIND=4) lock_id
BYTE(16)
END STRUCTURE !lksb

RECORD /lksb/ my_lksb
lock_value_block BYTE(16)
logical_name CHARACTER (LEN=n)
longword_signed INTEGER (KIND=4)
longword_unsigned INTEGER (KIND=4) 1
mask_byte INTEGER (KIND=1) ! (or BYTE)
mask_longword INTEGER (KIND=4)
mask_quadword INTEGER (KIND=8)
mask_word INTEGER (KIND=2)
mechanism_args INCLUDE '($CHFDEF)'
RECORD /CHFDEF2/ mechargs
! (For more information, see Section 14.5.)
null_arg %VAL(0) ! (or an unspecified optional argument)
octaword_signed INTEGER (KIND=4)(4)
octaword_unsigned INTEGER (KIND=4)(4) 1
page_protection INTEGER (KIND=4)
procedure INTEGER (KIND=4)
process_id INTEGER (KIND=4)
process_name CHARACTER (LEN=n)
quadword_signed INTEGER (KIND=8)
quadword_unsigned INTEGER (KIND=8) 1
rights_holder STRUCTURE /rights_holder/
INTEGER (KIND=4) rights_id
INTEGER (KIND=4) rights_mask
END STRUCTURE !rights_holder

RECORD /rights_holder/ my_rights_holder
rights_id INTEGER (KIND=4)
rab INCLUDE '($RABDEF)'
RECORD /RABDEF/ myrab
section_id INTEGER (KIND=4)(2) or INTEGER (KIND=8)
section_name CHARACTER (LEN=n)
system_access_id INTEGER (KIND=4)(2) or INTEGER (KIND=8)
time_name CHARACTER (LEN=23)
transaction_id INTEGER (KIND=4)(4)
uic INTEGER (KIND=4)
user_arg Any longword quantity
varying_arg Any appropriate type
vector_byte_signed BYTE(n)
vector_byte_unsigned BYTE(n) 1
vector_longword_signed INTEGER(KIND=4) (n)
vector_longword_unsigned INTEGER(KIND=4) (n) 1
vector_quadword_signed INTEGER(KIND=8) (n)
vector_quadword_unsigned INTEGER (KIND=8) (n) 1
vector_word_signed INTEGER (KIND=2) (n)
vector_word_unsigned INTEGER (KIND=2) (n) 1
word_signed INTEGER (KIND=2) (n)
word_unsigned INTEGER (KIND=2) (n) 1


1Unsigned data types are not directly supported by Compaq Fortran. However, in most cases you can substitute the signed equivalent, provided you do not exceed the range of the signed data structure.
2Where n can range from 1 to 65535. When passing character constant actual arguments in older Compaq Fortran 77 for OpenVMS VAX programs, see Section 2.3.9.
3The format used by floating-point (KIND=4) and (KIND=8) data in memory is determined by the FORTRAN command qualifier /FLOAT.

Many arguments to system services are optional. However, if you omit an optional argument, you must include a comma (,) to indicate the absence of that argument. For example, the SYS$TRNLNM system service takes five arguments. If you omit the first and the last two arguments, you must include commas to indicate their existence, as follows:


  ISTAT = SYS$TRNLNM(,'LNM$FILE_DEV','LOGNAM',,) 

An invalid reference results if you specify the arguments as follows:


  ISTAT = SYS$TRNLNM('LOGNAM',LENGTH,BUFFA) 

This reference provides only three arguments, not the required five.

When you omit an optional argument by including an extra comma, the compiler supplies a default value of zero (passed by immediate value).

10.7.4.1 Immediate Value Arguments

Value arguments are typically used when the description of the system service specifies that the argument is a "number," "mask," "mode," "value," "code," or "indicator." You must use either the cDEC$ ATTRIBUTES VALUE (see Section 10.3.2.3) or the %VAL built-in function (see Section 10.2.3) whenever this method is required.

Immediate value arguments are used for input arguments only.

10.7.4.2 Address Arguments

Use address arguments when the description of the system service specifies that the argument is "the address of." (However, refer to Section 10.7.4.3 to determine what to do when "the address of a descriptor" is specified.) In Compaq Fortran, this argument-passing method is called "by reference."

Because this method is the Compaq Fortran default for passing numeric arguments, you need to specify the cDEC$ ATTRIBUTES REFERENCE directive (see Section 10.3.2.3) or the %REF built-in function only when the data type of the argument is character.

The argument description also gives the hardware data type required.

For arguments described as "address of an entry mask" or "address of a routine," declare the argument value as an external procedure. For example, if a system service requires the address of a routine and you want to specify the routine HANDLER3, include the following statement in the declarations portion of your program:


  EXTERNAL HANDLER3 
This specification defines the address of the routine for use as an input argument.

Address arguments are used for both input and output.

Table 10-7 Variable Data Type Requirements
OpenVMS Type Required Input Argument Declaration Output Argument Declaration
Byte BYTE, INTEGER (KIND=1), INTEGER (KIND=2), INTEGER (KIND=4) BYTE, INTEGER (KIND=1)
Word INTEGER (KIND=2), INTEGER (KIND=4) INTEGER (KIND=2)
Longword INTEGER (KIND=4) INTEGER (KIND=4)
Quadword INTEGER (KIND=8) or INTEGER (KIND=4) (2) or properly dimensioned array INTEGER (KIND=8) or INTEGER (KIND=4) (2) or properly dimensioned array
Indicator LOGICAL  
Character string descriptor CHARACTER (LEN=n) CHARACTER (LEN=n)
Entry mask or routine EXTERNAL  

10.7.4.3 Descriptor Arguments

Descriptor arguments are used for input and output of character strings. Use a descriptor argument when the argument description specifies "address of a descriptor." Because this method is the Compaq Fortran default for character arguments, you need to specify the %DESCR built-in function only when the data type of the argument is not character.

On input, a character constant, variable, array element, or expression is passed to the system service by descriptor. On output, two items are needed:

In the following example of the Translate Logical Name system service (SYS$TRNLNM), the logical name LOGNAM is translated to its associated name or file specification. The output string and string length are stored in the variables EQV_BUFFER and W_NAMELEN, respectively:


  INCLUDE '($LNMDEF)' 
  INCLUDE '($SYSSRVNAM)' 
 
  STRUCTURE /LIST/ 
    INTEGER (KIND=2) BUF_LEN/255/ 
    INTEGER (KIND=2) ITEM_CODE/LNM$_STRING/ 
    INTEGER (KIND=4) TRANS_LOG 
    INTEGER (KIND=4) TRANS_LEN 
    INTEGER (KIND=4) END_ENTRY/0/ 
  END STRUCTURE    !LIST 
 
  CHARACTER (LEN=255) EQV_BUFFER 
  INTEGER (KIND=2)  W_NAMELEN 
 
  RECORD/LIST/ ITEM_LIST 
  ITEM_LIST.TRANS_LOG = %LOC(EQV_BUFFER) 
  ITEM_LIST.TRANS_LEN = %LOC(W_NAMELEN) 
 
  ISTAT = SYS$TRNLNM(, 'LNM$FILE_DEV', 'FOR$SRC', ,ITEM_LIST) 
  IF (ISTAT) PRINT *, EQV_BUFFER(:W_NAMELEN) 
  END 

10.7.4.4 Data Structure Arguments

Data structure arguments are used when the argument description specifies "address of a list," "address of a control block," or "address of a vector." The data structures required for these arguments are constructed in Compaq Fortran with structure declaration blocks and the RECORD statement. The storage declared by a RECORD statement is allocated in exactly the order given in the structure declaration, with no space between adjacent items. For example, the item list required for the SYS$GETJPI (or SYS$GETJPIW) system service requires a sequence of items of two words and two longwords each. By declaring each item as part of a structure, you ensure that the fields and items are allocated contiguously:


  STRUCTURE /GETJPI_STR/ 
          INTEGER (KIND=2) BUFLEN, ITMCOD 
          INTEGER (KIND=4) BUFADR, RETLEN 
  END STRUCTURE 
  ... 
  RECORD /GETJPI_STR/ LIST(5) 

If a given field is provided as input to the system service, the calling program must fill the field before the system service is called. You can accomplish this with data initialization (for fields with values that are known at compile time) and with assignment statements (for fields that must be computed).

When the data structure description requires a field that must be filled with an address value, use the %LOC built-in function to generate the desired address (see Section 10.2.2). When the description requires a field that must be filled with a symbolic value (system-service function code), you can define the value of the symbol by the method described in Section 10.7.1.

10.7.4.5 Examples of Passing Arguments

Example 10-4 shows a complete subroutine that uses a data structure argument to the SYS$GETJPIW system service:

Example 10-4 Subroutine Using a Data Structure Argument

!  Subroutine to obtain absolute and incremental values of process parameters: 
!  CPU time, Buffered I/O count, Direct I/O count, Page faults. 
 
      SUBROUTINE PROCESS_INFO(ABS_VALUES, INCR_VALUES) 
 
!  Declare the arguments and working storage 
 
      INTEGER (KIND=4) ABS_VALUES(4), INCR_VALUES(4), LCL_VALUES(4) 
      INTEGER (KIND=4) STATUS, I 
 
!  Declare the SYS$GETJPIW item list data structure in a structure declaration 
 
      STRUCTURE /GETJPI_STR/ 
              INTEGER (KIND=2)  BUFLEN /4/, ITMCOD /0/ 
              INTEGER (KIND=4)  BUFADR, RETLEN /0/ 
      END STRUCTURE 
 
!  Create a record with the fields defined in the structure declaration 
 
      RECORD /GETJPI_STR/ LIST(5) 
 
!  Declare the structure of an I/O Status Block 
 
      STRUCTURE /IOSB_STR/ 
           INTEGER (KIND=4) STATUS, RESERVED 
      END STRUCTURE 
 
!  Declare the I/O Status Block 
 
      RECORD /IOSB_STR/ IOSB         
 
!  Assign all static values in the item list 
 
      LIST(1).ITMCOD = JPI$_CPUTIM 
      LIST(2).ITMCOD = JPI$_BUFIO 
      LIST(3).ITMCOD = JPI$_DIRIO 
      LIST(4).ITMCOD = JPI$_PAGEFLTS 
 
!  Assign all item fields requiring addresses 
 
      LIST(1).BUFADR = %LOC(LCL_VALUES(1)) 
      LIST(2).BUFADR = %LOC(LCL_VALUES(2)) 
      LIST(3).BUFADR = %LOC(LCL_VALUES(3)) 
      LIST(4).BUFADR = %LOC(LCL_VALUES(4)) 
 
      STATUS = SYS$GETJPIW(,,,LIST,IOSB,,)  ! Perform system service call 
 
      IF (STATUS) STATUS = IOSB.STATUS      ! Check completion status 
      IF (.NOT. STATUS) CALL EXIT (STATUS) 
 
!  Assign the new values to the arguments 
 
      DO I=1,4 
         INCR_VALUES(I) = LCL_VALUES(I) - ABS_VALUES(I) 
         ABS_VALUES(I)  = LCL_VALUES(I) 
      END DO 
      RETURN 
 
      END SUBROUTINE PROCESS_INFO 

Example 10-5 is an example of the typical use of an I/O system service. The program invokes SYS$QIOW to enable Ctrl/C trapping. When the program runs, it prints an informational message whenever it is interrupted by a Ctrl/C, and then it continues execution:

Example 10-5 Ctrl/C Trapping Example

   PROGRAM TRAPC 
   INCLUDE '($SYSSRVNAM)' 
   INTEGER (KIND=2) TT_CHAN 
   COMMON TT_CHAN 
   CHARACTER (LEN=40) LINE 
 
!  Assign the I/O channel.  If unsuccessful stop; otherwise 
!  initialize the trap routine. 
 
   ISTAT = SYS$ASSIGN ('TT',TT_CHAN,,) 
   IF (.NOT. ISTAT) CALL LIB$STOP(%VAL(ISTAT)) 
   CALL ENABLE_CTRLC 
 
!     Read a line of input and echo it 
 
 10 READ (5,'(A)',END=999) LINE 
    TYPE *, 'LINE READ: ', LINE 
    GO TO 10 
999 END 
 
    SUBROUTINE ENABLE_CTRLC 
    INTEGER (KIND=2) TT_CHAN 
    COMMON TT_CHAN 
    EXTERNAL CTRLC_ROUT 
 
!   Include I/O symbols 
 
    INCLUDE '($IODEF)' 
    INCLUDE '($SYSSRVNAM)' 
 
!     Enable Ctrl/C trapping and specify CTRLC_ROUT 
!     as routine to be called when Ctrl/C occurs 
 
    ISTAT = SYS$QIOW( ,%VAL(TT_CHAN), %VAL(IO$_SETMODE .OR. IO$M_CTRLCAST),& 
        ,,,CTRLC_ROUT,,%VAL(3),,,) 
    IF (.NOT. ISTAT) CALL LIB$STOP(%VAL(ISTAT)) 
    RETURN 
    END SUBROUTINE ENABLE_CTRLC 
 
    SUBROUTINE CTRLC_ROUT 
    PRINT *, 'Ctrl/C pressed' 
    CALL ENABLE_CTRLC 
    RETURN 
 
    END SUBROUTINE CTRLC_ROUT 

For more examples of calling system services and RTL routines, see Appendix E and the Compaq Fortran Web site.

10.8 Calling Between Compaq Fortran 77 and Compaq Fortran

On OpenVMS Alpha systems, you can call a Compaq Fortran 77 subprogram from Compaq Fortran or call a Compaq Fortran subprogram from Compaq Fortran 77 (with very few exceptions). A Compaq Fortran 77 procedure and a Compaq Fortran procedure can also perform I/O to the same unit number.

10.8.1 Argument Passing and Function Return Values

The recommended rules for passing arguments and function return values between Compaq Fortran 77 and Compaq Fortran procedures are as follows:

Example 10-6 and Example 10-7 show passing an array from a Compaq Fortran program to a Compaq Fortran 77 subroutine that prints its value.

Example 10-6 shows the Compaq Fortran program (file ARRAY_TO_F77.F90). It passes the same argument as a target and a pointer. In both cases, it is received by reference by the Compaq Fortran 77 subroutine as a target (regular) argument. The interface block in Example 10-6 is not needed, but does allow data type checking.

Example 10-6 Compaq Fortran Program Calling a Compaq Fortran 77 Subroutine

 ! Pass arrays to f77 routine. File: ARRAY_TO_F77.F90 
 
 ! This interface block is not required, but must agree 
 ! with actual procedure. It can be used for type checking. 
 
 INTERFACE                    ! Procedure interface block 
   SUBROUTINE MEG(A) 
   INTEGER :: A(3) 
   END SUBROUTINE 
 END INTERFACE 
 
 INTEGER, TARGET :: X(3) 
 INTEGER, POINTER :: XP(:) 
 
 X = (/ 1,2,3 /) 
 XP => X                         
 
 CALL MEG(X)                  ! Call f77 implicit interface subroutine twice. 
 CALL MEG(XP)                
 END 

Example 10-7 shows the Compaq Fortran 77 program called by the Compaq Fortran program (file ARRAY_F77.FOR).

Example 10-7 Compaq Fortran 77 Subroutine Called by a Compaq Fortran Program

      ! Get array argument from F90. File: ARRAY_F77.FOR 
 
       SUBROUTINE MEG(A) 
       INTEGER A(3) 
       PRINT *,A 
       END 

These files (shown in Example 10-6 and Example 10-7) might be compiled, linked, and run as follows:


$ FORTRAN ARRAY_TO_F77.F90
$ FORTRAN /OLD_F77 ARRAY_F77.FOR
$ LINK/EXECUTABLE=ARRAY_TO_F77 ARRAY_TO_F77, ARRAY_F77
$ RUN ARRAY_TO_F77
           1           2           3 
           1           2           3 

In Example 10-6, because array A is not defined as a pointer in the interface block, the Compaq Fortran pointer variable XP is passed as target data by reference (address of the target data).

However, if the interface to the dummy argument had the POINTER attribute, the variable XP would be passed by descriptor. This descriptor would not work with the Compaq Fortran 77 program shown in Example 10-7.

For More Information:

10.8.2 Using Data Items in Common Blocks

To make global data available across Compaq Fortran and Compaq Fortran 77 procedures, use common blocks.

Common blocks are supported by both Compaq Fortran and Compaq Fortran 77, but modules are not supported by Compaq Fortran 77. Some suggestions about using common blocks follow:

10.8.3 I/O to the Same Unit Number

Compaq Fortran and Compaq Fortran 77 share the same run-time system, so you can perform I/O to the same unit number by Compaq Fortran and Compaq Fortran 77 procedures. For instance, a Compaq Fortran main program can open the file, a Compaq Fortran 77 function can issue READ or WRITE statements to the same unit, and the Compaq Fortran main program can close the file.

For More Information:

10.9 Calling Between Compaq Fortran and Compaq C

Before creating a mixed-language program that contains procedures written in Compaq Fortran and C, you need to know how to:

10.9.1 Compiling and Linking Files

Use the FORTRAN command to compile Compaq Fortran source files and CC to compile C source files. Link the object files using a LINK command.

For example, the following FORTRAN command compiles the Compaq Fortran main program EX1.F90 and the called C function UPEN.C:


$ FORTRAN EX1.F90 
$ CC UPEN.C

The following LINK command creates the executable program:


$ LINK EX1, UPEN

10.9.2 Procedures and External Names

When designing a program that will use Compaq Fortran and C, be aware of the following general rules and available Compaq Fortran capabilities:

10.9.3 Invoking a C Function from Compaq Fortran

You can use a function reference or a CALL statement to invoke a C function from a Compaq Fortran main or subprogram.

If a value will be returned, use a function reference:
C Function Declaration Compaq Fortran Function Invocation
data-type calc( argument-list)
{
...
} ;
EXTERNAL CALC
data-type :: CALC, variable-name
...
variable-name=CALC( argument-list)
...

If no value is returned, use a void return value and a CALL statement:
C Function Declaration Compaq Fortran Subroutine Invocation
void calc( argument-list)
{
...
} ;
EXTERNAL CALC
...
CALL CALC( argument-list)

10.9.4 Invoking a Compaq Fortran Function or Subroutine from C

A C main program or function can invoke a Compaq Fortran function or subroutine by using a function prototype declaration and invocation.

If a value is returned, use a FUNCTION declaration:
Compaq Fortran Declaration C Invocation
FUNCTION CALC( argument-list)
data-type :: CALC
...
END FUNCTION CALC
extern data-type calc( argument-list)
data-type variable-name;
variable-name=calc( argument-list);
...

If no value is returned, use a SUBROUTINE declaration and a void return value:
Compaq Fortran Declaration C Invocation
SUBROUTINE CALC( argument-list)
...
END SUBROUTINE CALC
extern void calc( argument-list)

calc( argument-list);
...

10.9.5 Equivalent Data Types for Function Return Values

Both C and Compaq Fortran pass most function return data by value, but equivalent data types must be used. The following table lists a sample of equivalent function declarations in Compaq Fortran and C. See Table 10-8 for a complete list of data declarations.
C Function Declaration Compaq Fortran Function Declaration
float rfort() FUNCTION RFORT()
REAL (KIND=4) :: RFORT
double dfort() FUNCTION DFORT()
REAL (KIND=8) :: DFORT
int ifort() FUNCTION IFORT()
INTEGER (KIND=4) :: IFORT

Because there are no corresponding data types in C, you should avoid calling Compaq Fortran functions of type COMPLEX and DOUBLE COMPLEX, unless you pass a struct of two float (or double float) C values (see Section 10.9.9).

The floating-point format used in memory is determined by the /FLOAT qualifier for both the FORTRAN and CC commands. When floating-point data is passed as an argument or is globally available, the same floating-point format must be used in memory by both the C and Compaq Fortran parts of your program.

The Compaq Fortran LOGICAL data types contain a zero if the value is false and a -1 if the value is true, which works with C conditional and if statements.

For More Information:

10.9.6 Argument Association and Equivalent Data Types

Compaq Fortran follows the argument-passing rules described in Section 10.1.4. These rules include:

10.9.6.1 Compaq Fortran Intrinsic Data Types

Compaq Fortran lets you specify the lengths of its intrinsic numeric data types with the following:

The following declarations of the integer An are equivalent (unless you specified the appropriate FORTRAN command qualifier):


INTEGER (KIND=4) :: A1 
INTEGER (4)      :: A2 
INTEGER          :: A3 
INTEGER*4        :: A4 

Character data in Compaq Fortran is passed and received by character descriptor. Dummy character arguments can use assumed-length for accepting character data of varying length.

For More Information:

On Compaq Fortran intrinsic data types, see Chapter 8.

10.9.6.2 Equivalent Compaq Fortran and C Data Types

The calling routine must pass the same number of arguments expected by the called routine. Also, for each argument passed, the manner (mechanism) of passing the argument and the expected data type must match what is expected by the called routine. For instance, C usually passes data by value and Compaq Fortran typically passes argument data by reference.

You must determine the appropriate data types in each language that are compatible. When you call a C routine from a Compaq Fortran main program, certain Fortran cDEC$ ATTRIBUTES directives may be useful to change the default passing mechanism (such as cDEC$ ATTRIBUTES C) as discussed in Section 10.3.2.

If the calling routine cannot pass an argument to the called routine because of a language difference, you may need to rewrite the called routine. Another option is to create an interface jacket routine that handles the passing differences.

When a C program calls a Compaq Fortran subprogram, all arguments must be passed by reference because this is what the Compaq Fortran routine expects. To pass arguments by reference, the arguments must specify addresses rather than values. To pass constants or expressions, their contents must first be placed in variables; then the addresses of the variables are passed.

When you pass the address of the variable, the data types must correspond as shown in Table 10-8 for OpenVMS Alpha systems:

Table 10-8 Compaq Fortran and C Data Types
Compaq Fortran Data Declaration C Data Declaration
integer (kind=2) x short int x;
integer (kind=4) x int x;
integer (kind=8) x __int64 x;
logical x unsigned x;
real x float x;
double precision x double x;
real (kind=16) x long double x; 1
complex (kind=4) x struct { float real, float imag; } x;
complex (kind=8) x struct { double dreal, double dimag } x;
complex (kind=16) x struct { long double dreal; long double dimag } x; 2
character(len=5) char x[5]


1Compaq C interprets this as either a 128-bit IEEE X_FLOAT or a 64-bit floating-point number, depending on the value specified in the CC /L_DOUBLE-SIZE qualifier. The default is /L_DOUBLE-SIZE=128.
2The equivalent C declaration is long double (may not support X_floating).

Be aware of the various sizes supported by Compaq Fortran for integer, logical, and real variables (see Chapter 8), and use the size consistent with that used in the C routine.

Compaq Fortran LOGICAL data types contain a zero if the value is false and a -1 if the value is true, which works with C language conditional and if statements.

The floating-point format used in memory is determined by the /FLOAT qualifier for both the FORTRAN and CC commands. When floating-point data is passed as an argument or is globally available, the same floating-point format must be used in memory both by the C and Compaq Fortran parts of your program.

Any character string passed by Compaq Fortran is not automatically null-terminated. To null-terminate a string from Compaq Fortran, use the CHAR intrinsic function (described in the Compaq Fortran Language Reference Manual).

10.9.7 Example of Passing Integer Data to C Functions

Example 10-8 shows C code that declares the two functions HLN and MGN. These functions display the arguments received. The function HLN expects the argument by value, whereas MGN expects the argument by reference (address).

Example 10-8 C Functions Called by a Compaq Fortran Program

/* get integer by value from Fortran. File: PASS_INT_TO_C.C */ 
 
void hln(int i) { 
    printf("99==%d\n",i); 
        i = 100; 
} 
 
/* get integer by reference from Fortran */ 
 
void mgn(int *i) { 
    printf("99==%d\n",*i); 
        *i = 101; 
} 

Example 10-9 shows the Compaq Fortran (main program) code that calls the two C functions HLN and MGN.

Example 10-9 Calling C Functions and Passing Integer Arguments

! Using %REF and %VAL to pass argument to C. File: PASS_INT_TO_CFUNCS.F90 
  INTEGER :: I 
  I = 99 
  CALL HLN(%VAL(I))       ! pass by value 
  PRINT *,"99==",I 
 
  CALL MGN(%REF(I))       ! pass by reference 
  PRINT *,"101==",I 
  I = 99 
  CALL MGN(I)             ! pass by reference 
  PRINT *,"101==",I 
  END 

The files (shown in Example 10-8 and Example 10-9) might be compiled, linked, and run as follows:


$ FORTRAN PASS_INT_TO_CFUNCS.F90 
$ CC PASS_INT_TO_C.C
$ LINK/EXECUTABLE=PASS_INT PASS_INT_TO_CFUNCS, PASS_INT_TO_C
$ RUN PASS_INT
99==99 
99==          99 
99==99 
101==         101 
99==99 
101==         101 

10.9.8 Example of Passing Complex Data to C Functions

Example 10-10 shows Compaq Fortran code that passes a COMPLEX (KIND=4) value (1.0,0.0) by immediate value to subroutine foo. To pass COMPLEX arguments by value, the compiler passes the real and imaginary parts of the argument as two REAL arguments by immediate value.

Example 10-10 Calling C Functions and Passing Complex Arguments

 
  ! Using !DEC$ATTRIBUTES to pass COMPLEX argument by value to F90 or C. 
  ! File: cv_main.f90  
 
  interface 
     subroutine foo(cplx) 
       !DEC$ATTRIBUTES C :: foo 
          complex cplx 
     end subroutine 
  end interface 
 
    complex(kind=4) c 
    c = (1.0,0.0) 
    call foo(c)             ! pass by value 
 
  end 

If subroutine foo were written in Compaq Fortran, it might look similar to the following example. In this version of subroutine foo, the COMPLEX parameter is received by immediate value. To accomplish this, the compiler accepts two REAL parameters by immediate value and stores them into the real and imaginary parts, respectively, of the COMPLEX parameter cplx.


 
  ! File: cv_sub.f90  
 
     subroutine foo(cplx) 
       !DEC$ATTRIBUTES C :: foo 
       complex cplx 
 
       print *, 'The value of the complex number is ', cplx 
 
     end subroutine 

If subroutine foo were written in C, it might look similar to the following example in which the complex number is explicitly specified as two arguments of type float.


  /* File: cv_sub.c */ 
 
  #include <stdio.h> 
 
  typedef struct {float c1; float c2;} complex; 
 
    void foo(complex c) 
  { 
      printf("The value of the complex number is (%f,%f)\n", c1, c2); 
  } 

The main routine (shown in Example 10-10) might be compiled and linked to the object file created by the compilation of the Compaq Fortran subroutine and then run as follows:


$ FORTRAN CV_MAIN.F90 
$ FORTRAN CV_SUB.F90
$ LINK/EXECUTABLE=CV.EXE CV_MAIN.OBJ, CV_SUB.OBJ 
$ RUN CV
1.000000,0.0000000E+00 

The main routine might also be compiled and linked to the object file created by the compilation of the C subroutine and then run as follows:


$ CC CV_SUB.C
$ LINK/EXECUTABLE=CV2.EXE CV_MAIN.OBJ CV_SUB.OBJ 
$ RUN CV2
1.000000,0.000000 

10.9.9 Handling User-Defined Structures

User-defined derived types in Compaq Fortran and user-defined C structures can be passed as arguments if the following conditions are met:

10.9.10 Handling Scalar Pointer Data

When Compaq Fortran passes scalar numeric data with the POINTER attribute, how the scalar numeric data gets passed depends on whether or not an interface block is provided:

When passing scalar numeric data without the pointer attribute, Compaq Fortran passes the actual data by reference. If the called C function declares the dummy argument for the passed data to be passed by a pointer, it accepts the actual data passed by reference (address) and handles it correctly.

Similarly, when passing scalar data from a C program to a Compaq Fortran subprogram, the C program can use pointers to pass numeric data by reference.

Example 10-11 shows a Compaq Fortran program that passes a scalar (nonarray) pointer to a C function. Variable X is a pointer to variable Y.

The function call to IFUNC1 uses a procedure interface block, whereas the function call to IFUNC2 does not. Because IFUNC1 uses a procedure interface block (explicit interface), the pointer is passed. Without an explicit interface IFUNC2, the target data is passed.

Example 10-11 Calling C Functions and Passing Pointer Arguments

! Pass scalar pointer argument to C. File: SCALAR_POINTER_FUNC.F90 
 
INTERFACE 
  FUNCTION IFUNC1(A) 
  INTEGER, POINTER :: A 
  INTEGER IFUNC1 
  END FUNCTION 
END INTERFACE 
 
INTEGER, POINTER :: X 
INTEGER, TARGET :: Y 
 
Y = 88 
X => Y 
PRINT *,IFUNC1(X)           ! Interface block visible, so pass 
                            ! pointer by reference. C expects "int **" 
 
PRINT *,IFUNC2(X)           ! No interface block visible, so pass 
                            ! value of "x" by reference. C expects "int *" 
PRINT *,Y 
END 

Example 10-12 shows the C function declarations that receive the Compaq Fortran pointer or target arguments from the example in Example 10-11.

Example 10-12 C Functions Receiving Pointer Arguments

/* C functions Fortran 90 pointers. File: SCALAR_POINTER.C  */ 
 
int ifunc1(int **a) { 
    printf("a=%d\n",**a); 
    **a = 99; 
    return 100; 
    } 
 
int ifunc2(int *a) { 
        printf("a=%d\n",*a); 
        *a = 77; 
        return 101; 
} 

The files (shown in Example 10-11 and Example 10-12) might be compiled, linked, and run as follows:


$ CC  SCALAR_POINTER.C
$ FORTRAN SCALAR_POINTER_FUNC.F90
$ LINK/EXECUTABLE=POINTER  SCALAR_POINTER, SCALAR_POINTER_FUNC
$ RUN POINTER
a=88 
         100 
a=99 
         101 
          77 

10.9.11 Handling Arrays

There are two major differences between the way the C and Compaq Fortran languages handle arrays:

Because of these two factors:

Compaq Fortran orders arrays in column-major order. The following Compaq Fortran array declaration for a 2 by 3 array creates elements ordered as y(1,1), y(2,1), y(1,2), y(2,2), y(1,3), y(2,3):


integer y(2,3) 

The Compaq Fortran declaration for a 2 by 3 array can be modified as follows to have the lowest bound 0 and not 1, resulting in elements ordered as y(0,0), y(1,0), y(0,1), y(1,1), y(0,2), y(1,2):


integer y(0:1,0:2) 

The following C array declaration for a 3 by 2 array has elements in row-major order as z[0,0], z[0,1], z[1,0], z[1,1], z[2,0], z[2,1]:


int z[3][2] 

To use C and Compaq Fortran array data:

When passing certain array arguments, if you use an explicit interface that specifies the dummy argument as an array with the POINTER attribute or an assumed-shape array, the argument is passed by array descriptor (see Section 10.1.7).

For information about performance when using multidimensional arrays, see Section 5.4.

Example 10-13 shows a C function declaration for function EXPSHAPE, which prints the passed explicit-shape array.

Example 10-13 C Function That Receives an Explicit-Shape Array

/* Get explicit-shape arrays from Fortran. File: EXPARRAY_FUNC.C */ 
 
void expshape(int  x[3][2]) { 
    int i,j; 
  for (i=0;i<3;i++) 
     for (j=0;j<2;j++) printf("x[%d][%d]=%d\n",i,j,x[i][j]); 
} 

Example 10-14 shows a Compaq Fortran program that calls the C function EXPSHAPE (shown in Example 10-13).

Example 10-14 Compaq Fortran Program That Passes an Explicit-Shape Array

! Pass an explicit-shape array from Fortran to C. File: EXPARRAY.F90 
 
INTEGER :: X(2,3) 
X = RESHAPE( (/(I,I=1,6)/), (/2,3/) ) 
 
CALL EXPSHAPE(X) 
END 

The files (shown in Example 10-13 and Example 10-14) might be compiled, linked, and run as follows:


$ FORTRAN EXPARRAY.F90
$ CC EXPARRAY_FUNC.C
$ LINK/EXECUTABLE=EXPARRAY EXPARRAY, EXPARRAY_FUNC
$ RUN EXPARRAY
x[0][0]=1 
x[0][1]=2 
x[1][0]=3 
x[1][1]=4 
x[2][0]=5 
x[2][1]=6 

For information on the use of array arguments with Compaq Fortran, see Section 10.1.5.

10.9.12 Handling Common Blocks of Data

The following notes apply to handling common blocks of data between Compaq Fortran and C:

The following examples show how C and Compaq Fortran code can access common blocks of data. The C code declares a global structure, calls the f_calc Compaq Fortran function to set the values, and prints the values:


struct S {int j; float k;}r; 
main() { 
f_calc(); 
printf("%d %f\n", r.j, r.k); 
} 

The Compaq Fortran function then sets the data values:


SUBROUTINE F_CALC() 
COMMON /R/J,K 
REAL K 
INTEGER J 
J = 356 
K = 5.9 
RETURN 
END SUBROUTINE F_CALC 

The C program then prints the structure member values 356 and 5.9 set by the Compaq Fortran function.


Previous Next Contents Index