Using Common External Data in Mixed-Language Programming

Common external data structures include Fortran common blocks, and C structures and variables that have been declared global or external. All of these data specifications create external variables, which are variables available to routines outside the routine that defines them.

This section applies only to Fortran/C and Fortran/MASM mixed-language programs because there is no way to share common data with Visual Basic. You must pass all data between Visual Basic and Fortran as arguments. This process can be streamlined by passing user-defined types between them, described in Handling User-Defined Types.

External variables are case sensitive, so the cases must be matched between different languages, as discussed in the section on naming conventions. Common external data exchange is described in the following sections:

Using Global Variables in Mixed-Language Programming

A variable can be shared between Fortran and C or MASM by declaring it as global (or COMMON) in one language and accessing it as an external variable in the other language. Visual Basic cannot access another language's global data or share its own. In Fortran/Basic programs, variables must be passed as arguments.

In Fortran, a variable can access a global parameter by using the EXTERN option for ATTRIBUTES. For example:

    !DEC$ ATTRIBUTES C, EXTERN :: idata
    INTEGER idata (20)

EXTERN tells the compiler that the variable is actually defined and declared global in another source file. If Fortran declares a variable external with EXTERN, the language it shares the variable with must declare the variable global.

In C, a variable is declared global with the statement:

  int idata[20]; // declared as global (outside of any function)

MASM declares a parameter global (PUBLIC) with the syntax:

PUBLIC [langtype] name

where name is the name of the global variable to be referenced, and the optional langtype is STDCALL or C. The option langtype, if present, overrides the calling convention specified in the .MODEL directive.

Conversely, Fortran can declare the variable global (COMMON) and other languages can reference it as external:

 ! Fortran declaring PI global
  REAL PI
  COMMON /PI/ PI ! Common Block and variable have the same name

In C, the variable is referenced as an external with the statement:

  //C code with external reference to PI
  extern float PI;

Note that the global name C references is the name of the Fortran common block, not the name of a variable within a common block. Thus, you cannot use blank common to make data accessible between C and Fortran. In the preceding example, the common block and the variable have the same name, which helps keep track of the variable between the two languages. Obviously, if a common block contains more than one variable they cannot all have the common block name. (See Using Fortran Common Blocks and C Structures.)

MASM can also access Fortran global (COMMON) parameters with the ATTRIBUTES EXTERN directive. The syntax is:

EXTERN [langtype] name

where name is the name of the global variable to be referenced, and the optional langtype is STDCALL or C.

Using Fortran Common Blocks and C Structures

To reference C structures from Fortran common blocks and vice versa, you must take into account the way the common blocks and structures differ in their methods of storing member variables in memory. Fortran places common block variables into memory in order as close together as possible, with the following rules:

Because of these padding rules, you must consider the alignment of C structure elements with Fortran common block elements and assure matching either by making all variables exactly equivalent types and kinds in both languages (using only 4-byte and 8-byte data types in both languages simplifies this) or by using the C pack pragmas in the C code around the C structure to make C data packing like Fortran's. For example:

 #pragma pack(2)
 struct {
         int N;
         char INFO[30];
 } examp;
 #pragma pack()

To restore the original packing, you must add #pragma pack( ) at the end of the structure. (Remember: Fortran module data can be shared directly with C structures with appropriate naming.)

Once you have dealt with alignment and padding, you can give C access to an entire common block or set of common blocks. Alternatively, you can pass individual members of a Fortran common block in an argument list, just as you can any other data item. Use of common blocks for mixed-language data exchange is discussed in the following sections:

Accessing Common Blocks and C Structures Directly

You can access Fortran common blocks directly from C by defining an external C structure with the appropriate fields, and making sure that alignment and padding between Fortran and C are compatible. The C and ALIAS ATTRIBUTES options can be used with a common block to allow mixed-case names.

As an example, suppose your Fortran code has a common block named Really, as shown:

   !DEC$ ATTRIBUTES ALIAS:'Really' :: Really
   REAL(4) x, y, z(6)
   REAL(8) ydbl
   COMMON / Really / x, y, z(6), ydbl

You can access this data structure from your C code with the following external data structure:

 #pragma pack(2)
 extern struct {
   float x, y, z[6];
   double ydbl;
 } Really;
 #pragma pack()

You can also access C structures from Fortran by creating common blocks that correspond to those structures. This is the reverse case from that just described. However, the implementation is the same because after common blocks and structures have been defined and given a common address (name), and assuming the alignment in memory has been dealt with, both languages share the same memory locations for the variables.

Passing the Address of a Common Block

To pass the address of a common block, simply pass the address of the first variable in the block, that is, pass the first variable by reference. The receiving C or Visual C++ module should expect to receive a structure by reference.

In the following example, the C function initcb receives the address of a common block with the first variable named n, which it considers to be a pointer to a structure with three fields:

Fortran source code:
!
  INTERFACE
     SUBROUTINE initcb (BLOCK)
       !DEC$ ATTRIBUTES C :: initcb
       !DEC$ ATTRIBUTES REFERENCE :: BLOCK
       INTEGER BLOCK
     END SUBROUTINE
  END INTERFACE
!
  INTEGER n
  REAL(8) x, y
  COMMON /CBLOCK/n, x, y
    .  .  .
  CALL initcb( n )

C source code:
 //
 #pragma pack(2)
 struct block_type
 {
   int n;
   double x;
   double y;
 };
 #pragma pack()
 //
 void initcb( struct block_type *block_hed )
  {
    block_hed->n = 1;
    block_hed->x = 10.0;
    block_hed->y = 20.0;
 }