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 (for systems based on IA-32 architecture) or unsigned 8-byte integer (for systems based on Intel® 64 architecture and those based on IA-64 architecture), 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 Options on Character Strings Passed as Arguments

Argument Default C C, REFERENCE STDCALL
(Windows*)
STDCALL, REFERENCE
(Windows*)

String

Passed by reference, along with length

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

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

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

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, DECORATE,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:

   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. An added benefit for using C strings on Windows* systems is that Windows API routines and most C library functions expect null-terminated strings.

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.

Handling Character Strings in Visual Basic and MASM

The following information on Visual Basic and MASM applies to Windows systems only.

Visual Basic strings must be passed by value to Fortran. Visual Basic strings are actually stored as structures containing length and location information. Passing by value dereferences the structure and passes just the string location, as Fortran expects. For example:

 ! In Basic
  Declare Sub forstr  Lib "forstr.dll" (ByVal Bstring as String)
  DIM bstring As String * 40 Fixed-length string
  CALL forstr(bstring)
 ! End Basic code
 ! In Fortran
  SUBROUTINE forstr(s)
  !DEC$ ATTRIBUTES STDCALL :: forstr
  !DEC$ ATTRIBUTES REFERENCE :: s
  CHARACTER(40) s
  s = 'Hello, Visual Basic!'
  END

The Fortran directive !DEC$ ATTRIBUTES STDCALL and the ATTRIBUTES REFERENCE property on variable arguments together inform Fortran not to expect the hidden length arguments to be passed from the Visual Basic calling program. The name in the Visual Basic program is specified as lowercase since STDCALL makes the Fortran name lowercase.

MASM does not add either a string length or a null character to strings by default. To append the string length, use the syntax:

  lenstring BYTE "String with length", LENGTHOF lenstring

To add a null character, append it by hand to the string:

 nullstring BYTE "Null-terminated string", 0

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. The following example shows the Fortran code for a return character function called MAKECHARS and a 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: