Handling Character Strings

By default, Intel Fortran passes a hidden length argument for strings. The hidden length argument consists of an unsigned 4-byte integer (IA-32 systems) or unsigned 8-byte integer (Intel® EM64T and Itanium®-based systems), always passed by value, added to the end of the argument list. You can alter the default way strings are passed by using attributes.

The following table shows the effect of various attributes on passed strings:

Effect of ATTRIBUTES Properties on Character Strings Passed as Arguments

Argument

Default

C

C, REFERENCE

String

Passed by reference, along with length

First character converted to INTEGER(4) and passed by value

Passed by reference, along with length

String with VALUE option

Error

First character converted to INTEGER(4) and passed by value

First character converted to INTEGER(4) and passed by value

String with REFERENCE option

Passed by reference, possibly along with length

Passed by reference, no length

Passed by reference, no length

The important things to note about the above table are:

Since all strings in C are pointers, C expects strings to be passed by reference, without a string length. In addition, C strings are null-terminated while Fortran strings are not. There are two basic ways to pass strings between Fortran and C: convert Fortran strings to C strings, or write C routines to accept Fortran strings.

To convert a Fortran string to C, choose a combination of attributes that passes the string by reference without length, and null terminate your strings. For example:

   INTERFACE      SUBROUTINE Pass_Str (string)        !DEC$ ATTRIBUTES C, ALIAS:'Pass_Str' :: Pass_Str        CHARACTER*(*) string        !DEC$ ATTRIBUTES REFERENCE :: string      END SUBROUTINE   END INTERFACE   CHARACTER(40) forstring   DATA forstring /'This is a null-terminated string.'C/

The following example shows the extension of using the null-terminator for the string in the Fortran DATA statement (see "C Strings" in the Intel® Fortran Language Reference):

   DATA forstring /'This is a null-terminated string.'C/

The C interface is:

  void Pass_Str (char *string)

To get your C routines to accept Fortran strings, C must account for the length argument passed along with the string address. For example:

! Fortran code
INTERFACE
SUBROUTINE Pass_Str (string)
CHARACTER*(*) string
END INTERFACE

The C routine must expect two arguments:

  void pass_str (char *string, unsigned int length_arg )

This interface handles the hidden-length argument, but you must still reconcile C strings that are null-terminated and Fortran strings that are not. In addition, if the data assigned to the Fortran string is less than the declared length, the Fortran string will be blank padded.

Rather than trying to handle these string differences in your C routines, the best approach in Fortran/C mixed programming is to adopt C string behavior whenever possible.

Fortran functions that return a character string using the syntax CHARACTER*(*) place a hidden string argument and the length of the string at the beginning of the argument list.

C functions that implement such a Fortran function call must declare this hidden string argument explicitly and use it to return a value. The C return type should be void. However, you are more likely to avoid errors by not using character-string return functions. Use subroutines or place the strings into modules or global variables whenever possible.

Returning Character Data Types

If a Fortran program expects a function to return data of type CHARACTER, the Fortran compiler adds two additional arguments to the beginning of the called procedure's argument list:

The called routine must copy its result through the address specified in the first argument. Example that follows shows the Fortran code for a return character function called MAKECHARS and corresponding C routine.

Example of Returning Character Types from C to Fortran

Fortran code
CHARACTER*10 CHARS, MAKECHARS
DOUBLE PRECISION X, Y
CHARS = MAKECHARS( X, Y )

Corresponding C Routine
void makechars ( result, length, x, y );
char *result;
int length;
double *x, *y;
{
...program text, producing returnvalue...
for (i = 0; i < length; i++ ) {
result[i] = returnvalue[i];
}
}

In the above example, the following restrictions and behaviors apply: