HP OpenVMS Systems Documentation

Content starts here

HP Fortran for OpenVMS
User Manual


Previous Contents Index

10.10.6.2 Equivalent HP 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 HP 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 HP 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.4.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 an HP Fortran subprogram, all arguments must be passed by reference because this is what the HP 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.

Table 10-8 HP Fortran and C Data Types
HP 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]

1HP 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 HP Fortran for integer, logical, and real variables (see Chapter 8), and use the size consistent with that used in the C routine.

HP 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 HP Fortran parts of your program.

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

10.10.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 an HP 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 HP 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.10.8 Example of Passing Complex Data to C Functions

Example 10-10 shows HP 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 HP 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 HP 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.10.9 Handling User-Defined Structures

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

  • The elements of the structures use the same alignment conventions (same amount of padding bytes, if any). The default alignment for C structure members is natural alignment. You can use the CC /MEMBER_ALIGNMENT qualifier (or pragma) to alter that alignment.
    Derived-type data in HP Fortran is naturally aligned (the compiler adds needed padding bytes) unless you specify the /ALIGNMENT=RECORDS=PACKED (or equivalent) qualifier (see Section 2.3.3).
  • All elements of the structures are in the same order.
    HP Fortran orders elements of derived types sequentially. However, those writing standard-conforming programs should not rely on this sequential order because the standard allows elements to be in any order unless the SEQUENCE statement is specified.
  • The respective elements of the structures have the same data type and length (kind), as described in Section 10.10.6.
  • The structure must be passed by reference (address).

10.10.10 Handling Scalar Pointer Data

When HP 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:

  • If you do not provide an interface block to pass the actual pointer, HP Fortran dereferences the HP Fortran pointer and passes the actual data (the target of the pointer) by reference.
  • If you do provide an interface block to pass the actual pointer, HP Fortran passes the HP Fortran pointer by reference.

When passing scalar numeric data without the pointer attribute, HP 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 an HP Fortran subprogram, the C program can use pointers to pass numeric data by reference.

Example 10-11 shows an HP 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 "y" by reference. C expects "int *"
PRINT *,Y
END

Example 10-12 shows the C function declarations that receive the HP 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.10.11 Handling Arrays

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

  • HP Fortran stores arrays with the leftmost subscript varying the fastest (column-major order). With C, the rightmost subscript varies the fastest (row-major order).
  • Although the default for the lower bound of an array in HP Fortran is 1, you can specify an explicit lower bound of 0 (zero) or another value. With C the lower bound is 0.

Because of these two factors:

  • When a C routine uses an array passed by an HP Fortran subprogram, the dimensions of the array and the subscripts must be interchanged and also adjusted for the lower bound of 0 instead of 1 (or a different value).
  • When an HP Fortran program uses an array passed by a C routine, the dimensions of the array and the subscripts must be interchanged. You also need to adjust for the lower bound being 0 instead of 1, by specifying the lower bound for the HP Fortran array as 0.

HP Fortran orders arrays in column-major order. The following HP 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 HP 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 HP Fortran array data:

  • Consider using a 0 (zero) as the lowest bounds in the HP Fortran array declaration.
    You may need to specify the HP Fortran declaration with a lowest bound 0 (not 1) for maintenance with C arrays or because of algorithm requirements.
  • Reverse the dimensions in one of the array declaration statements. For example, declare an HP Fortran array as 2 by 3 and the C array as 3 by 2. Similarly, when passing array row and column locations between C and HP Fortran, reverse the dimension numbers (interchange the row and column numbers in a two-dimensional array).

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.2.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 an HP Fortran program that calls the C function EXPSHAPE (shown in Example 10-13).

Example 10-14 HP 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 HP Fortran, see Section 10.2.5.

10.10.12 Handling Common Blocks of Data

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

  • In HP Fortran, you declare each common block with the COMMON statement. In C, you can use any global variable defined as a struct.
  • Data types must match unless you desire implicit equivalencing. If so, you must adhere to the alignment restrictions for HP Fortran data types.
  • If there are multiple routines that declare data with multiple COMMON statements and the common blocks are of unequal length, the largest of the sizes is used to allocate space.
  • A blank common block has a name of $BLANK.
  • You should specify the same alignment characteristics in C and HP Fortran. To specify the alignment of common block data items, specify the /ALIGN=COMMONS=NATURAL or /ALIGN=COMMONS=STANDARD qualifiers when compiling HP Fortran procedures using the FORTRAN command or specify data declarations carefully (see Section 5.3).

The following examples show how C and HP Fortran code can access common blocks of data. The C code declares a global structure, calls the f_calc HP 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 HP 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 HP Fortran function.


Previous Next Contents Index