[an error occurred while processing this directive]

HP OpenVMS Systems

C Programming Language
Content starts here HP C

HP C
User's Guide for OpenVMS Systems


Previous Contents Index

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(); 
 
int main(void) 
{ 
                             /*  Initialize structure name_desc * 
                              *  as string descriptor.          */ 
   static  $DESCRIPTOR(name_desc,"NEWPROC"); 
 
   return  SYS$SETPRN(&name_desc); 
} 

To test the results of the preceding example, do the following:


$ SHOW PROCESS       ! Note the process name. 
 
$ RUN example        ! Run the example. 
 
$ SHOW PROCESS       ! Note that the process name has changed. 

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

3.2.4 HP C Default Parameter-Passing Mechanisms

There are default parameter-passing mechanisms established for every data type you can use with HP C. Table 3-8 lists the HP 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 HP 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 HP C, you can call external routines written in other languages or HP 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, HP 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 HP C with routines written in other OpenVMS languages.

3.3.1 Calling HP FORTRAN

When calling HP FORTRAN from HP C or vice versa, note these considerations. HP FORTRAN argument lists and argument descriptors are usually allocated statically. When it is possible, and to optimize space and time, the HP FORTRAN compiler pools the argument lists and initializes them at compile time. Sometimes several calls may use the same argument list.

In HP C, you often use arguments as local variables, and modify them at will. If a HP C routine that modifies an argument is called from a HP FORTRAN routine, unintended and incorrect side effects may occur.

The following example shows a HP C routine that is invalid when called from HP FORTRAN:


void f(int *x)      /* x is a FORTRAN INTEGER passed by reference */ 
 
{ 
    /* The next assignment is OK.  It is permitted to modify what a 
     * FORTRAN argument list entry points to. */ 
    *x = 0;                /* ok */ 
 
    /* The next assignment is invalid.  It is not permitted to modify 
     * a FORTRAN argument list entry itself. */ 
    x = x + 1;                /* Invalid */ 
} 

Another problem is the semantic mismatch between strings in C and strings in HP FORTRAN. Strings in C vary in length and end in a null character. Strings in HP FORTRAN do not end in a null character and are padded with spaces to some fixed length. In general, this mismatch means that strings may not be passed between HP C and HP FORTRAN unless you do additional work. You may make a HP FORTRAN routine add a null character to a CHARACTER string before calling a HP C function. You may also write code that explicitly gets the length of a HP FORTRAN string from its descriptor and carefully pads the string with spaces after modifying it. An example later in this section shows a C function that carefully produces a proper string for HP FORTRAN.

Example 3-5 shows a HP C function calling a HP FORTRAN subprogram with a variety of data types. For most scalar types, HP FORTRAN expects arguments to be passed by reference but character data is passed by descriptor.

Example 3-5 HP C Function Calling a HP FORTRAN Subprogram

/* 
 *  Beginning of HP C function: 
 */ 
 
#include <stdio.h> 
#include <descrip.h>                 /* Get layout of descriptors */ 
 
extern int fort();                   /* Declare FORTRAN function */ 
 
main(void) 
{ 
    int i = 508; 
    float f = 649.0; 
    double d = 91.50; 
    struct { 
        short s; 
        float f; 
    } s = {-2, -3.14}; 
    auto $DESCRIPTOR(string1, "Hello, FORTRAN"); 
    struct dsc$descriptor_s string2; 
 
    /* "string1" is a FORTRAN-style string declared and initialized using the 
     * $DESCRIPTOR macro.  "string2" is also a FORTRAN-style string, but we are 
     * declaring and initializing it by hand. */ 
    string2.dsc$b_dtype = DSC$K_DTYPE_T;  /* Type is CHARACTER */ 
    string2.dsc$b_class = DSC$K_CLASS_S;  /* String descriptor */ 
    string2.dsc$w_length = 3;             /* Three characters in string */ 
    string2.dsc$a_pointer = "bye";        /* Pointer to string value */ 
 
    printf("FORTRAN result is %d\n", fort(&i, &f, &d, &s, &string1, &string2)); 
}   /* End of HP C function */ 
 
C 
C     Beginning of FORTRAN subprogram: 
C 
      INTEGER FUNCTION FORT(I, F, D, S, STRING1, STRING2) 
      INTEGER I 
      REAL F 
      DOUBLE PRECISION D 
      STRUCTURE /STRUCT/ 
      INTEGER*2 SHORT 
      REAL FLOAT 
      END STRUCTURE 
      RECORD /STRUCT/ S 
C     You can tell FORTRAN to use the length in the descriptor 
C     as done here for STRING1, or you can tell FORTRAN to ignore the 
C     descriptor and assume the string has a particular length as done 
C     for STRING2.  This choice is up to you. 
      CHARACTER*(*) STRING1 
      CHARACTER*3 STRING2 
 
      WRITE(5, 10) I, F, D, S.SHORT, S.FLOAT, STRING1, STRING2 
10    FORMAT(1X, I3, F8.1, D10.2, I7, F10.3, 1X, A, 2X, A) 
      FORT = -15 
      RETURN 
      END 
C     End of FORTRAN subprogram 

Example 3-5 produces the following output:


508   649.0  0.92D+02     -2    -3.140 Hello, FORTRAN  bye 
FORTRAN result is -15 

Example 3-6 shows a HP FORTRAN subprogram calling a HP C function. Since the HP C function is called from HP FORTRAN as a subroutine and not as a function, the HP C function is declared to have a return value of void .

Example 3-6 HP FORTRAN Subprogram Calling a HP C Function

C 
C     Beginning of FORTRAN subprogram: 
C 
      INTEGER I 
      REAL F(3) 
      CHARACTER*10 STRING 
 
C     Since this program does not have a C main program and you want 
C     to use HP C RTL functions from the C subroutine, you must call 
C     DECC$CRTL_INIT to initialize the run-time library. 
      CALL DECC$CRTL_INIT 
 
      I = -617 
      F(1) = 3.1 
      F(2) = 0.04 
      F(3) = 0.0016 
      STRING = 'HELLO' 
 
      CALL CSUBR(I, F, STRING) 
      END 
C     End of FORTRAN subprogram 
 
/* 
 *  Beginning of HP C function: 
 */ 
#include <stdio.h> 
#include <descrip.h>                       /* Get layout of descriptors */ 
 
void csubr(int *i,                         /* FORTRAN integer, by reference */ 
    float f[3],                            /* FORTRAN array, by reference */ 
    struct dsc$descriptor_s *string)       /* FORTRAN character, by descriptor */ 
{ 
    int j; 
 
    printf("i = %d\n", *i); 
 
    for (j = 0; j < 3; ++j) 
        printf("f[%d] = %f\n", j, f[j]); 
 
    /* Since FORTRAN character data is not null-terminated, you must use 
     * a counted loop to print the string. 
     */ 
    printf("string = \""); 
    for (j = 0; j < string->dsc$w_length; ++j) 
        putchar(string->dsc$a_pointer[j]); 
    printf("\"\n"); 
 
}   /*  End of HP C function  */ 

Example 3-6 produces the following output:


i = -617 
f[0] = 3.100000 
f[1] = 0.040000 
f[2] = 0.001600 
string = "HELLO     " 

Example 3-7 shows a C function that acts like a CHARACTER*(*) function in HP FORTRAN.

Example 3-7 HP C Function Emulating a HP FORTRAN CHARACTER*(*) Function

C 
C       Beginning of FORTRAN program: 
C 
        CHARACTER*9 STARS, C 
 
C       Call a C function to produce a string of three "*" left-justified 
C       in a nine-character field. 
        C = STARS(3) 
 
        WRITE(5, 10) C 
10      FORMAT(1X, '"', A, '"') 
        END 
C       End of FORTRAN program 
 
/* 
 *  Beginning of HP C function: 
 */ 
 
#include <descrip.h>                        /* Get layout of descriptors */ 
 
/* Routine "stars" is equivalent to a FORTRAN function declared as 
 * follows: 
 * 
 *        CHARACTER*(*) FUNCTION STARS(NUM) 
 *        INTEGER NUM 
 * 
 * Note that a FORTRAN CHARACTER function has an extra entry added to 
 * the argument list to represent the return value of the CHARACTER 
 * function.  This entry, which appears first in the argument list, 
 * is the address of a completely filled-in character descriptor.  Since 
 * the C version of a FORTRAN character function explicitly uses this 
 * extra argument list entry, the C version of the function is void! 
 * 
 * This example function returns a string that contains the specified 
 * number of asterisks (or "stars"). 
 * 
 */ 
 
void stars(struct dsc$descriptor_s *return_value, /* FORTRAN return value */ 
           int *num_stars)                 /* Number of "stars" to create */ 
{ 
    int i, limit; 
 
    /* A FORTRAN string is truncated if it is too large for the memory area 
     * allocated, and it is padded with spaces if it is too short.  Set limit 
     * to the number of stars to put in the string given the size of the area 
     * used to store it. */ 
    if (*num_stars < return_value->dsc$w_length) 
        limit = *num_stars; 
    else 
        limit = return_value->dsc$w_length; 
 
    /* Create a string of stars of the specified length up to the limit of the  
     * string size. */ 
    for (i = 0; i < limit; ++i) 
        return_value->dsc$a_pointer[i] = '*'; 
 
    /* Pad rest of string with spaces, if necessary. */ 
    for (; i < return_value->dsc$w_length; ++i) 
        return_value->dsc$a_pointer[i] = ' '; 
}  /*  End of HP C Function   */ 

Example 3-7 produces the following output:


"***      " 

3.3.2 Calling VAX MACRO

You can call a VAX MACRO routine from HP C or vice versa. However, like all interlanguage calls, it is necessary to make sure that the actual arguments correspond to the expected formal parameter types. Also, it is necessary to remember that C strings are null-terminated and to take special action in either the MACRO routine or the C routine to allow for this.

Example 3-8 shows a MACRO routine that calls a C routine with three arguments, passing one by value, one by reference, and one by descriptor. It is followed by the source for the called C routine.

Example 3-8 VAX MACRO Program Calling a HP C Function

;----------------------------------------------------------------------- 
; Beginning of MACRO program 
;----------------------------------------------------------------------- 
        .extrn  dbroutine        ; The C routine 
;----------------------------------------------------------------------- 
; Local Data 
;----------------------------------------------------------------------- 
 
        .psect        data        rd,nowrt,noexe 
 
        ft$$t_part_num:        .ascii /WidgitGadget/ 
        ft$$t_query_mode:        .ascii /I/ 
        ft$$s_query_mode =        <. - ft$$t_query_mode> 
        ft$$l_protocol_buff:        .blkl        1 
        ft$$kd_part_num_dsc: 
                        .word   12 
                        .word        0 
                        .address ft$$t_part_num 
 
;----------------------------------------------------------------------- 
; Entry Point 
;----------------------------------------------------------------------- 
        .psect        ft_code        rd,nowrt,exe 
        .entry dbtest        ^m<r2,r3,r4,r5,r6,r7,r8> 
 
;+ 
; call C routine for data base lookup 
;- 
        movl        #1,r3                
        pushal      ft$$kd_part_num_dsc             ; Descriptor for part number 
        pushal      ft$$t_query_mode                ; Mode to call 
        pushl       #1                              ; Status 
        calls       #3, dbroutine                   ; Check the data base 
99$: 
        ret 
 
        .end dbtest 
;----------------------------------------------------------------------- 
; End of MACRO program 
;----------------------------------------------------------------------- 
 
/* 
 *  Beginning of HP C code for dbroutine: 
 */ 
 
#include <stdio.h> 
#include <descrip.h> 
 
#include <stdlib.h> 
#include <string.h> 
 
 
/* Structure pn_desc is the format of the descriptor 
   passed by the macro routine. */ 
 
extern     struct 
       mydescript    { 
               short  pn_len; 
               short  pn_zero; 
               char   *pn_addr; 
               }; 
 
int  dbroutine (int status,                    /* Passed by value      */ 
                char *action,                  /* Passed by reference  */ 
                struct mydescript *name_dsc)   /* Passed by descriptor */ 
{ 
        char *part_name; 
 
        /* Allocate space to put the null-padded name string. */ 
        part_name = malloc(name_dsc->pn_len + 1); 
        memcpy( part_name,name_dsc -> pn_addr ,name_dsc -> pn_len); 
 
        /* Remember that C array bounds start at 0 */ 
        part_name[name_dsc -> pn_len] = '\0'; 
    
        printf (" Status is %d\n", status); 
        printf (" Length  is %d\n",name_dsc -> pn_len); 
        printf (" Part_name is %s\n",part_name);  
        printf (" Request is %c\n",*action);  
        status = 1; 
        return(status); 
}  /*  End of HP C code for dbroutine  */ 

Example 3-8 produces the following output:


 Status is 1 
 Length  is 12 
 Part_name is WidgitGadget 
 Request is I 

Example 3-9 shows a HP C program that calls a VAX MACRO program.

Example 3-9 HP C Program Calling a VAX MACRO Program

/* Beginning of HP C function  */ 
 
#include <stdio.h> 
#include <descrip.h> 
 
int zapit( int status, int *action, struct dsc$descriptor_s *descript); 
 
main(void) 
{ 
    int status=255, argh = 99;        
    int *action = &argh; 
    $DESCRIPTOR(name_dsc,"SuperEconomySize"); 
 
    printf(" Before calling ZAPIT: \n"); 
    printf(" Status was %d \n",status); 
    printf(" Action contained %d and *action contained %d \n" ,action, *action); 
    printf(" And the thing described by the descriptor was %s\n", 
            name_dsc.dsc$a_pointer); 
            
    if (zapit(status,action,&name_dsc) && 1) 
    { 
      printf(" Ack, the world has been zapped! \n");   
      printf(" Status is %d \n",status); 
      printf(" Action contains %d and *action contains %d \n" ,action, *action); 
      printf(" And the address of the thing described by the descriptor is %d\n", 
              name_dsc.dsc$a_pointer); 
 
    } 
 
}  /*  End of HP C function */ 
 
 
;----------------------------------------------------------------------- 
;  Beginning of VAX MACRO source code for zapit 
;----------------------------------------------------------------------- 
; Entry Point 
;----------------------------------------------------------------------- 
        .psect        ft_code        rd,nowrt,exe 
        .entry zapit        ^m<r2,r3,r4,r5,r6,r7,r8> 
 
;+ 
; Maliciously change parameters passed by the C routine. 
; 
; The first parameter is passed by value, the second by 
; reference, and the third by descriptor. 
;- 
        
        movl        4(ap), @8(ap)        ;Change the by-reference parameter 
                                         ;to the first parameter's value. 
 
        movl        12(ap), r2 
        movl        #0,4(r2)             ;Zap address of string in descriptor. 
 
        ; Return -1 to signal successful destruction. 
        movl        #-1,r0 
        ret 
 
        .end 
;----------------------------------------------------------------------- 
;  End of VAX MACRO source code for zapit 
;----------------------------------------------------------------------- 

Example 3-9 produces the following output:


 Before calling ZAPIT: 
 Status was 255 
 Action contained 2146269556 and *action contained 99 
 And the thing described by the descriptor was SuperEconomySize 
 Ack, the world has been zapped! 
 Status is 255 
 Action contains 2146269556 and *action contains 255 
 And the address of the thing described by the descriptor is 0 

3.3.3 Calling HP BASIC

Calling routines written in HP BASIC from HP C programs or vice versa is straightforward. By default, HP BASIC passes arguments by reference, except for arrays and strings, which are passed by descriptor. In some cases, these defaults may be overridden by explicitly specifying the desired parameter-passing mechanisms in the HP BASIC program. However, if an argument is a constant or an expression, the actual argument passed refers to a local copy of the specified argument's value.

Strings in HP BASIC are not terminated by a null character, which is done by HP C. As a result, passing strings between HP BASIC and HP C routines requires you to do additional work. You may choose to add an explicit null character to a HP BASIC string before passing it to a HP C routine, or you may prefer to code the HP C routine to obtain the string's length from its descriptor.

Example 3-10 shows a HP C program that calls a HP BASIC function with a variety of argument data types.

Example 3-10 HP C Function Calling a HP BASIC Function

/* 
 *  Beginning of HP C function: 
 */ 
 
#include <stdio.h> 
#include <descrip.h> 
 
        extern        int        basfunc (); 
 
        main(void) 
        { 
                int        i = 508; 
                float        f = 649.0; 
                double        d = 91.50; 
                struct 
                { 
                        short        s; 
                        float        f; 
                }        s = { -2, -3.14 }; 
                $DESCRIPTOR (string1, "A C string"); 
 
                printf ("BASIC returned %d\n", 
                        basfunc (&i, &f, &d, &s, &string1, "bye")); 
        }  /*  End of HP C function   */ 
 
 
        !  Beginning of the BASIC program 
 
        FUNCTION INTEGER basfunc (INTEGER i, REAL f, DOUBLE d, x s, & 
                                  STRING string1,                    & 
                                  STRING string2 = 3 BY REF) 
 
            RECORD        x 
                WORD    s 
                REAL    f 
            END RECORD x 
 
            PRINT 'i = '; i 
            PRINT 'f = '; f 
            PRINT 'd = '; d 
            PRINT 's::s = '; s::s 
            PRINT 's::f = '; s::f 
            PRINT 'string1 = '; string1 
            PRINT 'string2 = '; string2 
 
        END FUNCTION -15 
 
        ! End of the BASIC program 
 

Example 3-10 produces the following output:


        i =  508 
        f =  649 
        d =  91.5 
        s::s = -2 
        s::f = -3.14 
        string1 = A C string 
        string2 = bye 
        BASIC returned -15 

Example 3-11 shows a HP BASIC program that calls a HP C function.

Example 3-11 HP BASIC Program Calling a HP C Function

 
        ! Beginning of the BASIC program: 
 
        PROGRAM example 
 
            EXTERNAL STRING FUNCTION cfunc (INTEGER BY VALUE, & 
                                            INTEGER BY VALUE, & 
                                            STRING BY DESC) 
 
            s$ = cfunc (5, 3, "abcdefghi") 
            PRINT "substring is "; s$ 
 
        END PROGRAM 
 
        ! End of the BASIC program 
 
 
/* 
 *  Beginning of HP C function: 
 */ 
 
#include <descrip.h> 
 
int str$copy_dx(); 
 
 
        /* 
         *  This routine simulates a BASIC function whose return 
         *  value is a STRING.  It returns the substring that is `length' 
         *  characters long, starting from the offset `offset' (0-based) 
         *  in the input string described by the descriptor pointed to 
         *  by `in_str'. 
         */ 
 
        void        cfunc (struct dsc$descriptor_s *out_str, 
                       int offset, 
                       int length, 
                       struct dsc$descriptor_s *in_str) 
        { 
                /* Declare a string descriptor for the substring. */ 
                struct        dsc$descriptor        temp; 
 
                /* Check that the desired substring is wholly 
                   within the input string. */ 
                if (offset + length > in_str -> dsc$w_length) 
                        return; 
 
                /* Fill in the substring descriptor. */ 
                temp.dsc$w_length = length; 
                temp.dsc$a_pointer = in_str -> dsc$a_pointer + offset; 
                temp.dsc$b_dtype = DSC$K_DTYPE_T;        
                temp.dsc$b_class = DSC$K_CLASS_S; 
 
                /* Copy the substring to the return string. */ 
                str$copy_dx (out_str, & temp); 
        }  /*  End of HP C function  */ 

Example 3-11 produces the following output:


        substring is fgh 


Previous Next Contents Index