NAG C Header Files (Windows Implementation)

Calling NAG Fortran Library Routines
(implementations compiled with Compaq Visual Fortran)
from C Language Programs Using the NAG C Header File

Ian Hounam

NAG Ltd, Oxford

© The Numerical Algorithms Group Ltd, Oxford UK. 2002

1 Introduction

A great number of systems allow the C programmer to call other language routines. Indeed the ANSI standard definition of C provides a powerful argument checking facility that, given the correct definition of function prototypes, can facilitate cross language communication between C and, say, Fortran.

A header file containing the function prototypes can be included in the user's program to allow the C compiler to check argument passage. Such a header file has been created for the current NAG Fortran Library. This was done automatically from the Library source code in order to ensure its correctness. This document explains how to call Fortran routines from C using the NAG header file.

The information in this document is specific to NAG Library implementations compiled with Compaq Visual Fortran. The C Compiler used to test the conventions was Microsoft Visual C/C++.

2 Argument Types

The table below lists the mapping between relevant Fortran and C argument and function types.
   DOUBLE PRECISION D       double d;
   INTEGER I                int i;
   LOGICAL L                int l;
   CHARACTER*n S            char *s; int len_s; /* See below */
   DOUBLE COMPLEX Z         struct {double re,im;} z;

All arguments (except CHARACTER) are passed as pointers to a variable; this means that a constant must first be assigned to a variable and then the address of the variable passed.

As Fortran stores multi-dimension arrays in column major order whereas C stores in row major order, either

  1. the C routine must store and manipulate the transpose of the problem matrix, or
  2. the C routine must transpose the matrix before and after calling the Fortran routine.

Character arguments are passed as two arguments

  1. a pointer to the character string
  2. an int passed by reference containing the length of the string (for a character array this is the length of each element of the array) which is passed immediately after the string pointer

For example to call a routine called "NAGSUB" which in Fortran looks like this

      SUBROUTINE NAGSUB(A,B,C)
      CHARACTER A
      CHARACTER*3 B
      CHARACTER*5 C(2)

the C code looks like this.

  extern void __stdcall NAGSUB(char* a, int len_a,
                char *b, int len_b, char c[], int len_c);
  main()
    {
      char a = 'a';
      int len_a = 1;
      char b[] = "abc";
      int len_b = 3;
      char c[2][6] = {"abcde", "fghij"};
      int len_c = 5;

      NAGSUB(&a, len_a, b, len_b, (char *)c, len_c);
    }

Note that the char variables' declared length in the C program must allow space for the null termination in the C string.

The Fortran type DOUBLE COMPLEX (or COMPLEX*16) is provided in the NAG header files by the typedef "Complex", which expands to "struct {double re,im;}"

2.1 Alternate Reference Arguments Header

An alternate header file "nagmk20.hxx" is supplied for use in C++ programs. This defines all DOUBLE PRECISION, INTEGER, LOGICAL and DOUBLE COMPLEX scalars as C++ reference arguments. Hence it is not required to specify the "address of" operator for these arguments. In user supplied functions dereferencing such arguments is avoided. Also constants may be passed to such arguments.

3 Subroutines and Functions

CVF uses __stdcall calling conventions, except that routine names are converted to upper case. Fortran subroutines are declared as void functions in C. Procedure arguments, i.e. function or subroutine names, are passed by address in the normal C manner.

4 Complex functions

The CVF Fortran compiler uses the convention that Fortran DOUBLE COMPLEX functions are actually implemented as C void functions with an extra first argument which is a pointer to the result e.g.
      DOUBLE COMPLEX FUNCTION F(X)
      DOUBLE COMPLEX X

has the following prototype:

      extern void  __stdcall f(Complex *, Complex *);

and a user callable function, e.g S01EAF, looks like this

extern void  __stdcall S01EAF(Complex *return_value, const Complex *z,
                              int *ifail);

5 Multi-Dimension Arrays

There is no syntax in the C language to specify an arbitrary array dimension and it is not possible to know in advance the dimensions of the arrays in your program. The best that the C Header Files can do is to declare the multi-dimensional arrays as one dimension arrays with a comment stating the actual number of dimensions, e.g. for 2 dimensions:
int array[] /* 2 dimension */

and for 3 dimensions:

double array[] /* 3 dimension */

The prototype for a hypothetical NAG Fortran routine with a 2 dimensional DOUBLE PRECISION array argument would look like this:

extern void __stdcall NAGSUB(double[] /* 2 dimensions */);

A simple program to call this routine might look like this:

main ()
{
  double p[2][2];
  NAGSUB((double *)p);
}

Note that we need to cast the 2 dimensional C array actual argument to (double *).

The example prototype below shows how to call a hypothetical NAG routine that takes a single subroutine argument. This user supplied subroutine takes a 2 dimension DOUBLE PRECISION array and an integer which specifies the leading dimension of the Fortran array.

extern void __stdcall NAGSUB(void (*f) (double[] /* 2 dimension */,
                             int *));

The C code for the user supplied function is listed below. The 2 dimension array is passed as a pointer to double and the code must carry out array indexing using the dimension information passed from Fortran. In this case, the macro P uses the leading dimension of the Fortran array, which is the trailing dimension of the C array, to index into the array p. The array p is only referenced through this macro.

void __stdcall fun(double p[], int *tdp)
{
#define P(I,J) p[(I) + (*tdp)*(J)]
  P(0,0) = 0.0;
  P(1,1) = 1.0;
}

The main function looks like this:

main ()
{
  void __stdcall fun(double p[], int *tdp);
  NAGSUB(fun);
}

Example 2 below shows a complete program that illustrates these concepts.

6 Examples

The examples below are translations of NAG Fortran Library example programs into C. Where the Fortran code reads data, this data is coded directly into the initialisation of the C variables to make self-contained programs with no need for data files. Please refer to the NAG Fortran Library documentation for details of these example programs.

6.1 Example 1

This example shows how to call C05AJF using a procedure parameter, the function "f".

C05AJF Example Program.

6.2 Example 2

This example illustrates the use of two dimensional arrays in user supplied functions in the NAG Fortran Library routine D03PCF.

D03PCF Example Program

6.3 Example 3

This example illustrates the specification of two dimensional arrays in column major order in the C translation of the E04NFF example program. Results are printed by the NAG routine.

E04NFF Example Program

6.4 Example 4

The Fortran Library routine F01CTF is called with the matrices in the natural C row major order. The arguments TRANSA and TRANSB are used to specify that the matrices should be transposed. The result matrix is then transposed back to row major order using F01CRF. This example also illustrates character string arguments.

F01CTF Example Program

6.5 Example 5

DGBTRS is called with one matrix specified in column major order. Another matrix is loaded with its data using a macro to define the Fortran matrix ordering. Results are printed using X04CAF. This example also illustrates character string arguments.

DGBTRS/F07BEF Example Program



© The Numerical Algorithms Group Ltd, Oxford UK. 2002