![]() |
United States |
|
![]() | ||
![]() | ||
![]() | ||
![]() | ||
![]() | ||
|
||
![]() |
||
![]() |
![]() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Chapter 3
|
Register | Use |
---|---|
PC | Program counter |
SP | Stack pointer |
FP | Current stack frame pointer |
AP | Argument pointer |
R1 | Environment value (when necessary) |
R0, R1 | Function return value registers |
Register | Use |
---|---|
PC | Program counter |
SP | Stack pointer |
FP | Frame pointer for current procedure |
R25 | Argument information register |
R16 to R21,
F16 to F21 |
Argument list registers |
R0 | Function return value register |
By definition, any called routine can use registers R2 through R11 for computation, and the AP register as a temporary register.
In the calling standard, a stack is defined as a last-in/first-out (LIFO) temporary storage area that the system allocates for every user process. The system keeps information about each routine call in the current image on the call stack. Then, each time you call a routine, the system creates a structure on this call stack, known as the call frame. The call frame for each active process contains the following data:
When a routine completes execution, the system uses the frame pointer in the call frame of the current routine to locate the frame of the previous routine. The system then removes the call frame of the current routine from the stack.
Figure 3-1 shows the call stack and several call frames for VAX processors. Function A calls function B, which calls function C. When a function reaches a return statement or when control reaches the end of the function, the system uses the frame pointer in the call frame of the current function to locate the frame of the previous function. It then removes the call frame of the current function from the stack.
Figure 3-1 The Call Stack
A function is a routine that returns a single value to the calling
routine. The function value represents the value of the
expression in the
return
statement. According to the calling standard, a function value may be
returned as either an actual value or a condition value that indicates
success or failure.
3.1.3 The Argument List
The OpenVMS Calling Standard also defines a data structure called the argument list. You use an argument list to pass information to a routine and receive results.
On OpenVMS Alpha systems, an argument list is formed using registers R16 to R21 or F16 to F21, and a collection of quadwords in memory (depending on the number and type of the arguments).
On OpenVMS VAX systems, an argument list is a collection of longwords in memory that represents a routine parameter list and possibly includes a function value. Figure 3-2 shows the structure of a typical OpenVMS VAX argument list.
Figure 3-2 Structure of an OpenVMS VAX Argument List
The first longword must be present; this longword stores the number of arguments (the argument count: n) as an unsigned integer value in the low byte of the longword with a maximum of 255 arguments. The remaining 24 bits of the first longword are reserved for use by Compaq and should be 0. The longwords labeled arg1 through argn are the actual parameters, which can be any of the following addresses or value:
The argument list contains the parameters that are passed to the routine. Depending on the passing mechanisms for these parameters, the forms of the arguments contained in the argument list vary. For example, if you pass three arguments, the first by value, the second by reference, and the third by descriptor, the argument list would contain the value of the first argument, the address of the second, and the address of the descriptor of the third. Figure 3-3 shows this argument list.
Figure 3-3 Example of an OpenVMS VAX Argument List
For additional information on the OpenVMS calling standard,
see the OpenVMS Calling Standard.
3.2 Specifying Parameter-Passing Mechanisms
When you pass data between routines that are not written in the same OpenVMS language, you have to specify how you want that data to be represented and interpreted. You do this by specifying a parameter-passing mechanism.
The calling standard defines three ways to pass data in an argument list. When you code a reference to a non-Compaq C procedure, you must know how to pass each argument and write the function reference accordingly.
The following list describes the three argument-passing mechanisms:
The following sections outline each of these parameter-passing
mechanisms in more detail.
3.2.1 Passing Arguments by Immediate Value
By default, all values or expressions in a Compaq C function's argument list are passed by immediate value (except for X_FLOATING on OpenVMS Alpha systems, which is passed by reference). The expressions are evaluated and the results placed directly in the argument list of the CALL machine instruction.
The following statement declares the entry point of the Set Event Flag SYS$SETEF system service, which is used to set a specific event flag to 1:
/* Declare the function as a function returning type int. */ int SYS$SETEF(); |
The SYS$SETEF system service call requires one argument---the number of the event flag to be set---to be passed by immediate value. Compaq C for OpenVMS Systems converts linker-resolved variable names (such as the entry-point names of system service calls) to uppercase. You do not have to declare them in uppercase in your program (unless you compile your module with /NAMES=AS_IS). However, linker-resolved variable names must be declared and used with identical cases in each module. The documentation uses uppercase as a convention for referring to system service calls to highlight them in the text and examples.
Compaq C does not require you to declare a function or to specify the number or types of the function's arguments. However, if you call a function without declaring it or without providing argument information in the declaration, Compaq C does not check the types of the arguments in a call to that function. If you declare a function prototype, the compiler does check the arguments in a call to make sure that they have the same type. (See the Compaq C Language Reference Manual for more information on function prototypes.)
Like all system services, SYS$SETEF returns an integer value (the return status of the service) in register 0. Most system services return an integer completion status; therefore, the system service does not always have to be declared before it is used. The examples in this chapter declare system services for completeness.
In the OpenVMS System Services Reference Manual, you can find the specification of each service's arguments. SYS$SETEF, for example, takes one argument, an event flag number. It returns one of four status values, which are represented by the symbolic constants shown in Table 3-3.
Returned | Status | Description |
---|---|---|
SS$_WASCLR | Success | Flag was previously clear |
SS$_WASSET | Success | Flag was previously set |
SS$_ILLEFC | Failure | Illegal event flag number |
SS$_UNASEFC | Failure | Event flag not in associated cluster |
The system services manual also defines event flags as integers in the range 0 to 127, grouped in clusters of 32. Clusters 0 and 1, comprising flags 0 to 31 and 32 to 63, respectively, are local clusters available to any process, with the restriction that flags 24 to 31 are reserved for use by the OpenVMS system. There are many ways of passing valid event flag numbers from your Compaq C program to SYS$SETEF. One way is to use enum to define a subset of integers, as follows:
enum cluster0 {completion, breakdown, beginning} event; |
After the flag numbers are defined, call the SYS$SETEF service with the following code:
. . . int status; event = completion; . . . status = SYS$SETEF(event); /* Set event flag. */ . . . |
Figure 3-4 shows an argument being passed by immediate value; in this case, the event flag number passed to SYS$SETEF.
Figure 3-4 Passing Arguments by Immediate Value
Since argument lists consist of longwords, the calling standard dictates that immediate-value arguments be expressed in 32 bits. A single-precision, floating-point (F_floating) value is only 32 bits long, but the compiler promotes all arguments of type float to double (64 bits on a VAX processor) unless a function prototype declaration is used for the called function. This double-precision value is passed as two immediate values (two longwords).
The passing of double-precision immediate values is a violation of the calling standard for OpenVMS VAX systems, but is an allowed exception for Compaq C. |
On rare occasions, the float -to- double promotion requires some additional programming. For instance, the function OTS$POWRJ, in the VAX Common Run-Time Procedure Library, computes the value of a floating-point number raised to the power of a signed longword (in C terms, a float to the power of an int ). This function (and others like it) is called implicitly by high-level OpenVMS languages that have an exponentiation operator as part of the language. It requires that both its arguments be passed as immediate values, and it returns a single-precision ( float ) result. To pass a floating-point base to the procedure, you must use some method to avoid promoting float arguments. The recommended method is to declare the procedure using a function prototype declaration, as shown in Example 3-1.
Example 3-1 Passing Floating-Point Arguments by Immediate Value |
---|
/* This program shows how to pass a floating-point value, * * using prototypes to avoid promoting floating * * arguments to arguments of type double. */ #include <stdio.h> /* This declared function returns a value of type float. It * * should be called as follows: OTS$POWRJ(base, power), * * where base is of type float and power is of type int. */ float OTS$POWRJ(float, int); main(void) { /* To hold result of * * OTS$POWRJ */ float result; int power; /* Power argument */ float base; base = 3.145; /* Assign constant to base */ power = 2; result = OTS$POWRJ(base, power); printf("Result= %f\n", result); } |
The example does not show the methods for handling arithmetic errors that result from the operation performed. For more information on error handling in this context, and on the run-time library in general, see the VMS Run-Time Library Routines Volume.
When you pass a parameter by value, you pass a copy of the parameter
value to the routine instead of passing its address. Because the actual
value of the parameter is passed, the routine does not have access to
the storage location of the parameter; therefore, any changes that you
make to the parameter value in the routine do not affect the value of
that parameter in the calling routine.
3.2.2 Passing Arguments by Reference
Some system services and run-time library procedures expect arguments passed by reference. This means that the argument list contains the address of the argument rather than its value. This mechanism is also used by default by some programming languages, such as PL/I, and is available as an option in others, such as Pascal.
In C, you can use the ampersand operator (&) to pass an argument by reference; that is, the ampersand operator causes the argument's address to be passed. Note that an array name without brackets or a function name without parentheses in an argument list always results in passing the address of the array or function; the ampersand is unnecessary. You can also pass a pointer by value, which is the same as passing the item it points to by reference.
In the special case of argument lists, Compaq C in VAX C mode allows the ampersand operator to be used on constants as well. You should limit this use of the ampersand solely to calls to OpenVMS system functions to ensure portability of your Compaq C programs to other C compilers.
For example, the Read Event Flags (SYS$READEF) system service requires that its first argument be passed by immediate value and its second argument be passed by reference. SYS$READEF returns the status of all the event flags in a particular cluster. (Event flags are numbered from 0 to 127 and arranged in clusters of 32, such that flags 0 to 31 comprise cluster 0, flags 32 to 63, cluster 1, and so forth.)
The first SYS$READEF argument is any event flag number in the cluster of interest. The second argument is the address of a longword that receives the status of all 32 event flags in that cluster. In addition to the event-flag status value, the system service returns one of the status values shown in Table 3-4 expressed as a global symbol.
Returned | Status | Description |
---|---|---|
SS$_WASCLR | Success | Specified event flag was clear |
SS$_WASSET | Success | Specified event flag was set |
SS$_ACCVIO | Failure | Could not write to status longword |
SS$_ILLEFC | Failure | Event flag number was illegal |
SS$_UNASEFC | Failure | Cluster of interest not accessible |
Example 3-2 shows a call to the SYS$READEF system service from a Compaq C program.
Example 3-2 Passing Arguments by Reference |
---|
/* This program shows how to call system service SYS$READEF. */ #include <ssdef.h> #include <stdio.h> int SYS$READEF(); main(void) { /* Longword that receives * * the status of the * * event flag cluster. */ unsigned cluster_status; int return_status; /* Status: SYS$READEF. */ /* Argument values for * * SYS$READEF. */ enum cluster0 { completion, breakdown, beginning } event; . . . event = completion; /* Event flag in cluster 0. */ /* Obtain status of * * cluster 0. Pass value * * of event and address * * of cluster_status. */ |
return_status = SYS$READEF(event, &cluster_status); /* Check for successful * * call */ if (return_status != SS$WASCLR && return_status != SS$WASSSET) { /* Handle the error here. */ . . . } else { /* Check bits of interest in cluster_status here. */ . . . } } |
Previous | Next | Contents | Index |
![]() |
privacy statement and legal notices |