NAG C Header File (Linux/Unix and Windows Implementations)

Calling NAG Fortran Library Routines
from C/C++ Language Programs Using the NAG C Header File

Shah Datardina and Ian Hounam

Updated for Mark 23 by Sarah Turner

NAG Ltd, Oxford

© The Numerical Algorithms Group Ltd, Oxford UK. 2001, 2006, 2009, 2012

1 Introduction

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

A header file containing the function prototypes can be included in the user's program to allow the C/C++ compiler to check argument passage. Such a header file (nagmk23.h) has been created for the current NAG Fortran Library. This document explains how to call Fortran routines from C and C++ using the NAG Header File on Windows and Linux/Unix Systems. Current users of NAG header files may prefer to skip to Section 8.

2 Declaration of Fortran Routine Names in C/C++

Because case is not significant in Fortran, compilers convert names to a standard case. Most Linux and Unix compilers convert the name to lower case and append an underscore, e.g., X01AAF becomes x01aaf_.

Generally under Windows, names are converted to upper case. However with some compilers, e.g. the Intel Fortran compiler on 32-bit Windows with the option /iface:cvf an additional qualifier is attached to the subprogram name, i.e., X01AAF becomes __stdcall X01AAF. This is the standard calling convention adopted by Microsoft for the WIN32 API.

3 Argument Types

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

In C all scalar arguments 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.

On the other hand in C++, scalar arguments may be passed as references with the result that all scalar arguments become C++ reference arguments. This C Header File caters for C++ compilers and uses reference arguments. Hence the "address of" operator must not be used for these arguments. In user supplied functions dereferencing such arguments is also avoided. Also constants may be passed to such arguments.

Character arguments are passed as two arguments

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

All Linux/Unix Fortran compilers append this argument to the end of the argument list. Under Windows, the Intel Fortran compiler places the length at the end of the argument list by default. However, with the /iface:cvf option, the length of the character array is passed immediately after the string pointer, i.e., the compiler option /iface:mixed_str_len_arg is turned on. Note also that with /iface:cvf the standard calling convention (__stdcall) is enforced.

For some compilers/systems, the type of the length parameter is long or __int64. See Section 6 for details.

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)

With most compilers the C code looks like this.

  extern void nagsub_(char* a, char *b, char c[],
                     int len_a, int len_b, int len_c);
  main()
    {
      char a = 'a';
      int len_a = 1;
      char b[] = "abc";
      int len_b = 3;
      char c[2][6] = {"abcde", "fghij"}; /* Note the value 6 to allow
                                            for the null termination character */
      int len_c = 5;

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

The C code looks like this when the Fortran code is compiled with 32-bit Windows Intel Fortran using the option /iface:cvf

  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"}; /* Note the value 6 to allow
                                            for the null termination character */
      int len_c = 5;

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

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

The Fortran type COMPLEX*16 (or COMPLEX(KIND=0.0d0)) is provided in the NAG Header File by the typedef "Complex", which expands to "struct {double re,im;}"

4 Subroutine and Function Types

Fortran subroutines are declared as void functions in C.

Fortran functions will map as shown in the table above for data types, except for COMPLEX*16 functions and CHARACTER functions (see below).

Procedure arguments, i.e. function or subroutine names, are passed by address in the normal C manner.

5 COMPLEX*16 functions

The code examples in this section use the Unix conventions. On 32-bit Windows with the Intel Fortran Compiler using the /iface:cvf option, the __stdcall attribute should be used.

5.1 Most Unix and Windows Compilers

With newer compilers such as NAG Fortran, the HP-UX and Sun SPARC Solaris (64-bit implementation), COMPLEX*16 FUNCTIONs return a structure identical to the "Complex" typedef in the NAG C Header File, e.g.
      COMPLEX*16 FUNCTION F(X)
      COMPLEX*16 X

has the following prototype in C:

Complex (*f)(Complex *)
and a user callable function, e.g S01EAF, looks like this
extern Complex s01eaf_(const Complex *z,int *ifail);

5.2 Older Unix (e.g. 32-bit Sun SPARC Solaris) and Intel Fortran compilers on Linux (32- and 64-bit)

Some older compilers, such as the Sun SPARC Solaris 32-bit Fortran compiler, and Linux versions of the Intel Fortran compiler use the convention that Fortran COMPLEX*16 functions are actually implemented as C void functions with an extra first argument which is a pointer to the result e.g.

the prototype for the user supplied function F with these compilers is the following

      extern void  f(Complex *, Complex *);

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

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

5.3 IBM AIX

With the native Fortran compiler on IBM AIX, the C programmer wishing to access Fortran COMPLEX*16 FUNCTIONs has real problems. The conventions used by the native Fortran compiler on this system does not allow the C programmer to access the return value of COMPLEX*16 FUNCTIONs directly because the COMPLEX*16 return value is stored in registers that do not map to any C data type.

As it is impossible to access the return value of a COMPLEX*16 FUNCTION from C, another solution is to write a Fortran "jacket" routine to convert the COMPLEX*16 FUNCTION to a SUBROUTINE with an extra initial argument containing a pointer to the return value. The "jacket" routine then calls S01EAF.

For example to call S01EAF, write a jacket routine called S01EAFJ which would have the following prototype.

extern void s01eafj_(Complex *ret_val, CONST Complex *z,
                     int *ifail);
The jacket routine is then called from the C program rather than S01EAF.
      SUBROUTINE S01EAFJ(RET_VAL, Z, IFAIL)
      COMPLEX*16 RET_VAL, Z, S01EAF
      INTEGER IFAIL
      RET_VAL = S01EAF(Z, IFAIL)
      END
This routine can be compiled and linked with the C files and NAG Fortran Library in the normal way.

Similar jacket routines can be written for user supplied functions.

The supplied C Header File does not contain prototypes for these jacket functions. You may need to modify these prototypes appropriately.

6 Character functions

A character function is implemented as a void function with two extra arguments added to the start of the argument list, the first is a pointer to the returned string and the second its length.

e.g.

      CHARACTER*10 FUNCTION F(I)
is called thus:
     extern void f_(char *,int,int *);
      char c[10];
      int clen = 10,i;
      f_(&c,clen,&i)

The Intel Fortran 64-bit compiler on Linux, the gfortran compiler in ILP64 mode (-fdefault-integer-8), and the HP-UX 64-bit compiler use long instead of int for the hidden length argument. The Intel Fortran 64-bit compiler on Windows uses __int64 for this argument.

7 Multi-Dimension Arrays

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

  1. the C/C++ routine must store and manipulate the transpose of the problem matrix, or
  2. the C/C++ routine must transpose the matrix before and after calling the Fortran routine.
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 File 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 code examples in this section are for the Intel Fortran Compiler on 32-bit Windows with the /iface:cvf option. On other systems the __stdcall attribute should be omitted.

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 dimension */);

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.

8 The nagmk23.h header file

In the past we have provided a number of header files for our Windows and Linux/Unix C/C++ users. Since Mark 22, we have provided just the one header file which we believe will cater to the needs of most of our users. If you find that this header file does not meet your needs please contact us at support@nag.co.uk.

At Mark 23, the NAG C Header File provides the following variables which should be defined as required when compiling:

/* Define LONG_CHARLEN
   if string length parameters use type long
#define LONG_CHARLEN
*/

/* Define INT64_CHARLEN
   if string length parameters use type __int64
#define INT64_CHARLEN
*/

/* Define LONG_INTEGER
   if integer parameters use type long
#define LONG_INTEGER
*/

/* Define INT64_INTEGER
   if integer parameters use type __int64
#define INT64_INTEGER
*/

/* Define USE_STDCALL
   if the stdcall calling convention is being used
#define USE_STDCALL
*/

/* Define RETURN_COMPLEX_PARAM
   if complex valued functions implemented as void functions
   with an extra output parameter
#define RETURN_COMPLEX_PARAM
*/

These variables may either be set as compiler options or by modifying the header file itself (for example, to uncomment the relevant #define statement(s).)

The following NAG Fortran Library products have been tested with this header file and require the variables to be defined as shown below:

This is summarised in the table below:

Product Code    USE_STDCALL   RETURN_COMPLEX_PARAM   LONG_CHARLEN   INT64_CHARLEN   LONG_INTEGER   INT64_INTEGER 
FLDLL234ML Yes Yes        
FLL6A23DFL            
FLL6A23DHL     Yes   Yes  
FLL6I23DCL   Yes Yes      
FLLUX23DCL   Yes        
FLW3223DCL            
FLW6I23DCL       Yes    

(Note that the INT64_INTEGER variable has been provided in case it is required for future implementations.)

If in doubt as to which variables to define for NAG Fortran or SMP Libraries not listed above, please contact us.

The C Header File contains an 'extern "C"' declaration for C++ compilers, i.e.

#ifdef __cplusplus
extern "C" {
#endif
(with a matching "}" at the end of the file). As described in section 3, scalar arguments are passed by reference, so it follows that C++ users must not supply the address of scalar variables.

9 Linking your program

It is always necessary to link your program with the run time libraries of the Fortran compiler used to build the NAG Library you are linking to. This can be achieved on most UNIX systems by using this Fortran compiler to do the actual linking, e.g., with [F77] being the Fortran compiler used and [CC] your C compiler:
[CC] -c myprog.c
[F77] -o myprog myprog.o -lnag_nag
On some systems this will not work and in some circumstances it is necessary to link using ld or [CC], in which case it is necessary to specify the Fortran run time libraries in the link command. These libraries may be documented in the Fortran compiler documentation. They may also be distributed along with the NAG Library you are linking to.

10 Examples

The examples below are translations of NAG Fortran Library example programs into C. For these examples, 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. Further examples, some of which have separate data files, are included in the accompanying materials. C++ versions of the examples are also provided. Please refer to the NAG Fortran Library documentation for details of all these example programs.

Note that at Mark 23, the NAG Fortran Library for Win32 Applications (FLDLL234ML) can be called via the "most systems" examples as well as via the "Win32 with CVF interface and STDCALL" examples, but the latter is provided for compatibility with earlier versions of the NAG C Header File.

10.1 Example 1

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

C05AJF Example Program (most systems)

C05AJF Example Program (Win32 with CVF interface and STDCALL)

10.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 (most systems)

D03PCF Example Program (Win32 with CVF interface and STDCALL)

10.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 (most systems)

E04NFF Example Program (Win32 with CVF interface and STDCALL)

10.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 (most systems)

F01CTF Example Program (Win32 with CVF interface and STDCALL)

10.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 (most systems)

DGBTRS/F07BEF Example Program (Win32 with CVF interface and STDCALL)