Handling Character Strings

By default, Visual Fortran passes a hidden length argument for strings. The hidden length argument consists of an unsigned 4-byte integer (ia32 systems) or unsigned 8-byte integer (ia64 systems), always passed by value, immediately following the address of the character string. 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 STDCALL C, REFERENCE STDCALL, REFERENCE
String Passed by reference, along with length First character converted to INTEGER(4) and passed by value First character converted to INTEGER(4) and passed by value Passed by reference, along with length 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, on ia32 systems:

   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/

On ia64 systems, the first !DEC$ ATTRIBUTES line would omit the leading underscore and be as follows:
   !DEC$ ATTRIBUTES C, ALIAS:'Pass_Str' :: Pass_Str

This example shows the extension of using the null-terminator for the string in the Fortran DATA statement (see C Strings):
   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 __stdcall 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. Another good reason for using C strings is that Win32 APIs 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 address 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.

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 argument s 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