Passing data from one language to another

The Corresponding data types in Fortran and C table shows the data types available in the XL Fortran and C languages. Further sections detail how Fortran arguments can be passed by reference to C programs. To use the Fortran 2003 Standard interoperability features, see the BIND attribute and ISO_C_BINDING module .

Passing arguments between languages

Table 17. Corresponding data types in Fortran and C When calling Fortran procedures, the C routines must pass arguments as pointers to the types listed in this table.
XL Fortran Data Types XL C/C++ Data Types
Notes:
  1. Requires C/C++ compiler -qlongdbl option.
INTEGER(1), BYTE signed char
INTEGER(2) signed short
INTEGER(4) signed int
INTEGER(8) signed long long
REAL, REAL(4) float
REAL(8), DOUBLE PRECISION double
REAL(16) long double (see note 1)
COMPLEX, COMPLEX(4) float _Complex
COMPLEX(8), DOUBLE COMPLEX double _Complex
COMPLEX(16) long double _Complex (see note 1)
LOGICAL(1) unsigned char
LOGICAL(2) unsigned short
LOGICAL(4) unsigned int
LOGICAL(8) unsigned long long
CHARACTER char
CHARACTER(n) char[n]
Integer POINTER void *
Array array
Sequence-derived type structure (with C/C++ -qalign=packed option)
Notes:
  1. In interlanguage communication, it is often necessary to use the %VAL built-in function, or the standards-compliant VALUE attribute, and the %REF built-in function that are defined in Passing arguments by reference or by value.
  2. C programs automatically convert float values to double and short integer values to integer when calling an unprototyped C function. Because XL Fortran does not perform a conversion on REAL(4) quantities passed by value, you should not pass REAL(4) and INTEGER(2) by value to a C function that you have not declared with an explicit interface.
  3. The Fortran-derived type and the C structure must match in the number, data type, and length of subobjects to be compatible data types.
Related information:
One or more sample programs under the directory /opt/ibmcmp/xlf/11.1/samples illustrate how to call from Fortran to C.

To use the Fortran 2003 Standard interoperability features provided by XL Fortran, see the Language interoperability features section.

Passing global variables between languages

To access a C data structure from within a Fortran program or to access a common block from within a C program, follow these steps:

  1. Create a named common block that provides a one-to-one mapping of the C structure members. If you have an unnamed common block, change it to a named one. Name the common block with the name of the C structure.
  2. Declare the C structure as a global variable by putting its declaration outside any function or inside a function with the extern qualifier.
  3. Compile the C source file to get packed structures.

 program cstruct                         struct mystuff {
 real(8) a,d                                    double a;
 integer b,c                                    int b,c;
 .                                              double d;
 .                                       };
 common /mystuff/ a,b,c,d
 .                                       main() {
 .
 end                                     }

If you do not have a specific need for a named common block, you can create a sequence-derived type with the same one-to-one mapping as a C structure and pass it as an argument to a C function. You must compile the C source file to get packed structures or put #pragmas into the struct.

Common blocks that are declared THREADLOCAL are thread-specific data areas that are dynamically allocated by compiler-generated code. A static block is still reserved for a THREADLOCAL common block, but the compiler and the compiler's runtime environment use it for control information. If you need to share THREADLOCAL common blocks between Fortran and C procedures, your C source must be aware of the implementation of the THREADLOCAL common block. For more information, see the Directives section, and Appendix. Sample Fortran programs.

Common blocks that are declared THREADPRIVATE can be accessed using a C global variable that is declared as THREADPRIVATE.

Passing character types between languages

One difficult aspect of interlanguage calls is passing character strings between languages. The difficulty is due to the following underlying differences in the way that different languages represent such entities:

If you are writing both parts of the mixed-language program, you can make the C routines deal with the extra Fortran length argument, or you can suppress this extra argument by passing the string using the %REF function. If you use %REF, which you typically would for pre-existing C routines, you need to indicate where the string ends by concatenating a null character to the end of each character string that is passed to a C routine:

! Initialize a character string to pass to C.
               character*6 message1 /'Hello\0'/
! Initialize a character string as usual, and append the null later.
               character*5 message2 /'world'/

! Pass both strings to a C function that takes 2 (char *) arguments.
               call cfunc(%ref(message1), %ref(message2 // '\0'))
               end

For compatibility with C language usage, you can encode the following escape sequences in XL Fortran character strings:

Table 18. Escape sequences for character strings
Escape Meaning
\b Backspace
\f Form feed
\n New-line
\r Carriage return
\t Tab
\0 Null
\' Apostrophe (does not terminate a string)
\" Double quotation mark (does not terminate a string)
\ \ Backslash
\x x, where x is any other character (the backslash is ignored)

If you do not want the backslash interpreted as an escape character within strings, you can compile with the -qnoescape option.

Passing arrays between languages

Fortran stores array elements in ascending storage units in column-major order. C stores array elements in row-major order. Fortran array indexes start at 1, while C array indexes start at 0.

The following example shows how a two-dimensional array that is declared by A(3,2) is stored in Fortran and C.

Table 19. Corresponding array layouts for Fortran and C The Fortran array reference A(X,Y,Z) can be expressed in C as a[Z-1][Y-1][X-1]. Keep in mind that although C passes individual scalar array elements by value, it passes arrays by reference.
  Fortran Element Name C Element Name
Lowest storage unit A(1,1) A[0][0]
  A(2,1) A[0][1]
  A(3,1) A[1][0]
  A(1,2) A[1][1]
  A(2,2) A[2][0]
Highest storage unit A(3,2) A[2][1]

To pass all or part of a Fortran array to another language, you can use Fortran 90/Fortran 95 array notation:

REAL, DIMENSION(4,8) :: A, B(10)

! Pass an entire 4 x 8 array.
CALL CFUNC( A )
! Pass only the upper-left quadrant of the array.
CALL CFUNC( A(1:2,1:4) )
! Pass an array consisting of every third element of A.
CALL CFUNC( A(1:4:3,1:8) )
! Pass a 1-dimensional array consisting of elements 1, 2, and 4 of B.
CALL CFUNC( B( (/1,2,4/) ) )

Where necessary, the Fortran program constructs a temporary array and copies all the elements into contiguous storage. In all cases, the C routine needs to account for the column-major layout of the array.

Any array section or noncontiguous array is passed as the address of a contiguous temporary unless an explicit interface exists where the corresponding dummy argument is declared as an assumed-shape array or a pointer. To avoid the creation of array descriptors (which are not supported for interlanguage calls) when calling non-Fortran procedures with array arguments, either do not give the non-Fortran procedures any explicit interface, or do not declare the corresponding dummy arguments as assumed-shape or pointers in the interface:

! This explicit interface must be changed before the C function
! can be called.
INTERFACE
  FUNCTION CFUNC (ARRAY, PTR1, PTR2)
    INTEGER, DIMENSION (:) :: ARRAY          ! Change this : to *.
    INTEGER, POINTER, DIMENSION (:) :: PTR1  ! Change this : to *
                                             ! and remove the POINTER
                                             ! attribute.
    REAL, POINTER :: PTR2                    ! Remove this POINTER
                                             ! attribute or change to TARGET.
  END FUNCTION
END INTERFACE

Passing pointers between languages

Integer POINTERs always represent the address of the pointee object and must be passed by value:

CALL CFUNC(%VAL(INTPTR))

Fortran 90 POINTERs can also be passed back and forth between languages but only if there is no explicit interface for the called procedure or if the argument in the explicit interface does not have a POINTER attribute or assumed-shape declarator. You can remove any POINTER attribute or change it to TARGET and can change any deferred-shape array declarator to be explicit-shape or assumed-size.

Because of XL Fortran's call-by-reference conventions, you must pass even scalar values from another language as the address of the value, rather than the value itself. For example, a C function passing an integer value x to Fortran must pass &x. Also, a C function passing a pointer value p to Fortran so that Fortran can use it as an integer POINTER must declare it as void **p. A C array is an exception: you can pass it to Fortran without the & operator.

Passing arguments by reference or by value

To call subprograms written in languages other than Fortran (for example, user-written C programs, or operating system routines), the actual arguments may need to be passed by a method different from the default method used by Fortran. C routines, including those in system libraries such as libc.so, require you to pass arguments by value instead of by reference. (Although C passes individual scalar array elements by value, it passes arrays by reference.)

You can change the default passing method by using the %VAL built-in function or VALUE attribute and the %REF built-in function in the argument list of a CALL statement or function reference. You cannot use them in the argument lists of Fortran procedure references or with alternate return specifiers.

%REF
Passes an argument by reference (that is, the called subprogram receives the address of the argument). It is the same as the default calling method for Fortran except that it also suppresses the extra length argument for character strings.
%VAL
Passes an argument by value (that is, the called subprogram receives an argument that has the same value as the actual argument, but any change to this argument does not affect the actual argument).

You can use this built-in function with actual arguments that are CHARACTER(1), BYTE, logical, integer, real, or complex expressions or that are sequence-derived type. Objects of derived type cannot contain pointers, arrays, or character structure components whose lengths are greater than one byte.

You cannot use %VAL with actual arguments that are array entities, procedure names, or character expressions of length greater than one byte.

%VAL causes XL Fortran to pass the actual argument as 32-bit or 64-bit intermediate values.

In 32-bit Mode

If the actual argument is one of the following:

  • An integer or a logical that is shorter than 32 bits, it is sign-extended to a 32-bit value.
  • An integer or a logical that is longer than 32 bits, it is passed as two 32-bit intermediate values.
  • Of type real or complex, it is passed as multiple 64-bit intermediate values.
  • Of sequence-derived type, it is passed as multiple 32-bit intermediate values.

Byte-named constants and variables are passed as if they were INTEGER(1). If the actual argument is a CHARACTER(1), the compiler pads it on the left with zeros to a 32-bit value, regardless of whether you specified the -qctyplss compiler option.

In Linux® 32-bit only, structures are actually copied, and then the address of the copy is passed by value.

In 64-bit mode

If the actual argument is one of the following:

  • An integer or a logical that is shorter than 64 bits, it is sign-extended to a 64-bit value.
  • Of type real or complex, it is passed as multiple 64-bit intermediate values.
  • Of sequence-derived type, it is passed as multiple 64-bit intermediate values.

Byte-named constants and variables are passed as if they were INTEGER(1). If the actual argument is a CHARACTER(1), the compiler pads it on the left with zeros to a 64-bit value, regardless of whether you specified the -qctyplss compiler option.

If you specified the -qautodbl compiler option, any padded storage space is not passed except for objects of derived type.

VALUE attribute
Specifies an argument association between a dummy and an actual argument that allows you to pass the dummy argument with the value of the actual argument. Changes to the value or definition status of the dummy argument do not affect the actual argument.

You must specify the VALUE attribute for dummy arguments only.

You must not use the %VAL or %REF built-in functions to reference a dummy argument with the VALUE attribute, or the associated actual argument.

A referenced procedure that has a dummy argument with the VALUE attribute must have an explicit interface.

A dummy argument with the VALUE attribute can be of character type if you omit the length parameter or specify it using an initialization expression with a value of 1.

You must not specify the VALUE attribute with the following:

  EXTERNAL FUNC
  COMPLEX XVAR
  IVARB=6

  CALL RIGHT2(%REF(FUNC))       ! procedure name passed by reference
  CALL RIGHT3(%VAL(XVAR))       ! complex argument passed by value
  CALL TPROG(%VAL(IVARB))       ! integer argument passed by value
  END

Explicit interface for %VAL and %REF

You can specify an explicit interface for non-Fortran procedures to avoid coding calls to %VAL and %REF in each argument list, as follows:

INTERFACE
    FUNCTION C_FUNC(%VAL(A),%VAL(B)) ! Now you can code "c_func(a,b)"
        INTEGER A,B                  ! instead of
    END FUNCTION C_FUNC              ! "c_func(%val(a),%val(b))".
END INTERFACE

Example with VALUE attribute

Program validexm1
  integer :: x = 10, y = 20
  print *, 'before calling: ', x, y
  call intersub(x, y)
  print *, 'after calling: ', x, y

  contains
  subroutine intersub(x,y)
    integer, value ::  x
    integer y
    x = x + y
    y = x*y
    print *, 'in subroutine after changing: ', x, y
  end subroutine
end program validexm1

Expected output:

before calling: 10 20
in subroutine after changing: 30 600
after calling: 10 600

Passing complex values to/from gcc

Passing complex values between Fortran and Gnu C++ depends on what is specified for the -qfloat=[no]complexgcc suboption. If -qfloat=complexgcc is specified, the compiler uses Linux conventions when passing or returning complex numbers. -qfloat=nocomplexgcc is the default.

For -qfloat=complexgcc in 32-bit mode, the compiler passes COMPLEX *8 values in 2 general-purpose registers (GPRs) and COMPLEX *16 values in 4 GPRs. In 64-bit mode, COMPLEX *8 values are passed in 1 GPR, and COMPLEX *16 in 2 GPRs. For -qfloat=nocomplexgcc, COMPLEX *8 and COMPLEX *16 values are passed in 2 floating-point registers (FPRs). COMPLEX *32 values are always passed in 4 FPRs for both -qfloat=complexgcc and -qfloat=nocomplexgcc (since gcc does not support COMPLEX*32).

For -qfloat=complexgcc in 32-bit mode, COMPLEX *8 values are returned in GPR3-GPR4, and COMPLEX *16 in GPR3-GPR6. In 64-bit mode, COMPLEX *8 values are returned in GPR3, and COMPLEX*16 in GPR 3-GPR4. For -qfloat=nocomplexgcc, COMPLEX *8 and COMPLEX *16 values are returned in FPR1-FPR2. For both -qfloat=complexgcc and -qfloat=nocomplexgcc, COMPLEX *32 is always returned in FPR1-FPR4.

Returning values from Fortran functions

XL Fortran does not support calling certain types of Fortran functions from non-Fortran procedures. If a Fortran function returns a pointer, array, or character of nonconstant length, do not call it from outside Fortran.

You can call such a function indirectly:

SUBROUTINE MAT2(A,B,C)    ! You can call this subroutine from C, and the
                          ! result is stored in C.
INTEGER, DIMENSION(10,10) :: A,B,C
C = ARRAY_FUNC(A,B)       ! But you could not call ARRAY_FUNC directly.
END

Arguments with the OPTIONAL attribute

When you pass an optional argument by reference, the address in the argument list is zero if the argument is not present.

When you pass an optional argument by value, the value is zero if the argument is not present. The compiler uses an extra register argument to differentiate that value from a regular zero value. If the register has the value 1, the optional argument is present; if it has the value 0, the optional argument is not present.

Related information:
See Order of arguments in argument list.