DEC C
User's Guide for OpenVMS Systems


Previous Contents Index

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, DEC 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 DEC 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.

Table 3-4 Status Values of SYS$READEF
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 DEC 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.    */ 
            . 
            . 
            . 
      } 
} 

3.2.3 Passing Arguments by Descriptor

A descriptor is a structure that describes the data type, size, and address of a data structure. According to the OpenVMS Calling Standard, you must pass a descriptor by placing its address in the argument list. To pass an argument by descriptor from a DEC C program, perform the following steps:

  1. Write a structure declaration that models the required descriptor. This involves including the <descrip.h> header file to define struct tags for all the forms of descriptors.
  2. Assign appropriate values to the structure members.
  3. Use the structure name, with an ampersand operator (&) in the function reference, to put the structure's address in the argument list.

DEC C never passes arguments by descriptor by default; you must take explicit action to pass an argument by descriptor. Also, if you write structure or union names in a function's argument list without the ampersand operator, the structure or union is passed by immediate value to the called function. You pass arguments by descriptor only when the called function is written in another language and explicitly requires this mechanism.

Note

The passing of structures as immediate values can be a violation of the OpenVMS calling standard if the entire structure is larger than one longword of memory. This type of argument passing is an allowed exception for DEC C.

There are several classes of descriptor. Each class requires that certain bits be set in the first longword of the descriptor. For more information about the descriptors and their formats, see the OpenVMS Programming Interfaces: Calling a System Routine. You can model descriptors in DEC C as follows:


struct  dsc$descriptor 
   { 
      unsigned  short  dsc$w_length; /*  Length of data         */ 
      char  dsc$b_dtype              /*  Data type code         */ 
      char  dsc$b_class              /*  Descriptor class code  */ 
      char  *dsc$a_pointer           /*  Address of first byte  */ 
   }; 

In this model, the variable dsc$w_length is a 16-bit word containing the length of the entire data; the unit (for example, bit or byte) in which the length is measured depends on the descriptor class. The member dsc$b_dtype is a byte containing a numeric code; the code denotes the data type of the data. The class member dsc$b_class is another byte code giving the descriptor class. Table 3-5 shows the valid class codes.

Table 3-5 Valid Class Codes
Class Code Symbolic Name Descriptor Class
1 DSC$K_CLASS_S Scalar, string
2 DSC$K_CLASS_D Dynamic string descriptor
3 --- Reserved by Digital
4 DSC$K_CLASS_A Array
5 DSC$K_CLASS_P Procedure
6 DSC$K_CLASS_PI Procedure incarnation
7 DSC$K_CLASS_J Reserved by Digital
8 DSK$K_CLASS_JI This is obsolete
9 DSC$K_CLASS_SD Decimal scalar string
10 DSC$K_CLASS_NCA Noncontiguous array
11 DSC$K_CLASS_VS Varying string
12 DSC$K_CLASS_VSA Varying string array
13 DSC$K_CLASS_UBS Unaligned bit string
14 DSC$K_CLASS_UBA Unaligned bit array
15 DSC$K_CLASS_SB String with bounds descriptor
16 DSC$K_CLASS_UBSB Unaligned bit string with bounds descriptor
17-190 --- Reserved by Digital
191 DSC$K_CLASS_BFA Basic file array
192-255 --- Reserved for customer applications

The atomic data types shown in Table 3-6 are supported by DEC C; all others are not directly supported by the language. See the OpenVMS Programming Interfaces: Calling a System Routine manual for a complete list of atomic class codes.

Table 3-6 Atomic Data Types
Class Code Symbolic Name Descriptor Class
2 DSC$K_DTYPE_BU Byte (unsigned)
3 DSC$K_DTYPE_WU Word (unsigned)
4 DSC$K_DTYPE_LU Longword (unsigned)
6 DSC$K_DTYPE_B Byte integer (signed)
7 DSC$K_DTYPE_W Word integer (signed)
8 DSC$K_DTYPE_L Longword integer (signed)
10 DSC$K_DTYPE_F F_floating
11 DSC$K_DTYPE_D D_floating
27 DSC$K_DTYPE_G G_floating
52 DSC$K_DTYPE_FS IEEE S_floating
53 DSC$K_DTYPE_FT IEEE T_floating

The last member of the structure model, dsc$a_pointer , points to the first byte of the data.

To pass an argument by descriptor, you define and assign values to the data following normal C programming practices. You must define a dsc$descriptor structure and assign the data's address to the dsc$a_pointer member. You must also assign appropriate values to the members dsc$w_length , dsc$b_dtype , and dsc$b_class . For the specific requirements of each descriptor class, see the OpenVMS Programming Interfaces: Calling a System Routine manual.

For example, the Set Process Name (SYS$SETPRN) system service, which enables a process to establish or change its process name, accepts a process name as a fixed-length character string passed by descriptor. The character string can have from 1 to 15 characters. The system service returns status values that are represented by the symbolic constants shown in Table 3-7.

Table 3-7 Status Values of SYS$SETPRN
Returned Status Description
SS$_NORMAL Success Normal completion
SS$_ACCVIO Failure Inaccessible descriptor
SS$_DUPLNAM Failure Duplicate process name
SS$_IVLOGNAM Failure Invalid length

Example 3-3 shows a call to this system service from a DEC C program.

Example 3-3 Passing Arguments by Descriptor

/*  This program shows a call to system service SYS$SETPRN.    */ 
 
#include <ssdef.h> 
#include <stdio.h> 
                                   /*  Define structures for   * 
                                    *   descriptors            */ 
#include <descrip.h> 
 
int SYS$SETPRN(); 
 
int main(void) 
{ 
   int  ret;                       /*  Define return status of * 
                                    *   SYS$SETPRN             */ 
 
                                   /*  Name the descriptor     */ 
   struct  dsc$descriptor_s  name_desc; 
 
   char  *name =  "NEWPROC";       /*  Define new process name */ 
      . 
      . 
      . 
                                   /*  Length of name WITHOUT  * 
                                    *   null terminator        */ 
   name_desc.dsc$w_length = strlen(name); 
 
                                   /*  Put address of          * 
                                    *   shortened string in    * 
                                    *   descriptor             */ 
   name_desc.dsc$a_pointer =  name; 
 
                                   /*  String descriptor class */ 
   name_desc.dsc$b_class =  DSC$K_CLASS_S; 
 
                                   /*  Data type: ASCII string */ 
   name_desc.dsc$b_dtype =  DSC$K_DTYPE_T; 
      . 
      . 
      . 
   ret =  SYS$SETPRN(&name_desc); 
 
   if (ret != SS$_NORMAL)          /*  Test return status      */ 
      fprintf(stderr, "Failed to set process name\n"), 
      exit(ret); 
      . 
      . 
      . 
} 

In Example 3-3, the call to SYS$SETPRN must use the ampersand operator; otherwise, name_desc , rather than its address, is passed.

Although this example explicitly sets individual fields in its name_desc string descriptor, in practice, the run-time initialization of compile-time constant string descriptors is not performed in this manner. Instead, the fields of compile-time constant descriptors are usually initialized with initialized structures of storage class static .

For the purpose of string descriptor initialization, DEC C provides a simple preprocessor macro in the <descrip.h> header file. This macro is named $DESCRIPTOR. It takes two arguments, which it uses in a standard DEC C structure declaration. The first argument is an identifier specifying the name of the descriptor to be declared and initialized. The second argument is a pointer to the data byte to be used as the value of the descriptor. Since a character-string constant is interpreted as an initialized pointer to char , you may specify the second argument as a simple string constant. You may use the $DESCRIPTOR macro in any context where a declaration may be used. The scope of the declared string descriptor identifier name is identical to the scope of a simple struct definition as expanded by the macro.

Example 3-4 shows a variant of the program in Example 3-3. Here, the $DESCRIPTOR macro is used to create a compile-time string descriptor and to pass it to the SYS$SETPRN system service routine. In Example 3-4, the program returns the status value returned by SYS$SETPRN to DCL for interpretation.

Example 3-4 Passing Compile-Time String Descriptors

/*  This program returns the status value returned by          * 
 *  SYS$SETPRN.                                                */ 
 
#include  <descrip.h>              /*  Define $DESCRIPTOR      * 
                                    *   macro                  */ 
int  SYS$SETPRN(); 
 
main(void) 
{ 
                                   /*  Initialize structure    * 
                                    *   name_desc as string    * 
                                    *   descriptor             */ 
   static  $DESCRIPTOR(name_desc,"NEWPROC"); 
 
   return  SYS$SETPRN(&name_desc); 
} 

The $DESCRIPTOR macro is used in further examples in this chapter.

3.2.4 DEC C Default Parameter-Passing Mechanisms

There are default parameter-passing mechanisms established for every data type you can use with DEC C. Table 3-8 lists the DEC C data types you can use with each parameter-passing mechanism. Asterisks appear next to the default parameter-passing mechanism for that particular data type.

Table 3-8 Valid Parameter-Passing Mechanisms in DEC C
Data Type By Reference By Descriptor By Value
Variables Yes Yes Yes*
Constants Yes (VAX C mode only) Yes Yes*
Expressions No No Yes*
Array elements Yes Yes Yes*
Entire array Yes* Yes No
String constants Yes* Yes No
Structures and unions Yes Yes Yes*
Functions Yes* Yes No

You must use the appropriate parameter-passing mechanisms whenever you call a routine written in some other OpenVMS language or some prewritten system routine.

3.3 Interlanguage Calling

In DEC C, you can call external routines written in other languages or DEC C routines from routines written in other languages as either functions or subroutines. When you call an external routine as a function, a single value is returned. When you call an external routine as a subroutine (a void function), any values are returned in the argument list.

By default, DEC C passes all arguments by immediate value with the exception of arrays and functions; these are passed by reference. Table 3-9 lists the default passing mechanisms for other OpenVMS languages.

Table 3-9 Default Passing Mechanisms
Language Arrays Numeric Data Character Data
MACRO No default No default No default
Pascal Reference Reference Descriptor
BASIC Descriptor Reference Descriptor
COBOL N/A Reference Reference
FORTRAN Reference Reference Descriptor

The following sections describe the methods involved in using DEC C with routines written in other OpenVMS languages.


Previous Next Contents Index