HP OpenVMS Systems Documentation |
HP Fortran for OpenVMS
|
Previous | Contents | Index |
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.
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] |
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 |
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 |
User-defined derived types in HP Fortran and user-defined C structures can be passed as arguments if the following conditions are met:
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:
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 |
There are two major differences between the way the C and HP Fortran languages handle arrays:
Because of these two factors:
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:
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:
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 |