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