Calling NAG FL Interface Routines in the NAG Library
from C/C++ Language Programs Using the NAG C Header Files
Shah Datardina, Ian Hounam, Sarah Turner and Edward Smyth
NAG Ltd, Oxford
© The Numerical Algorithms Group Ltd, Oxford UK. 2001, 2006, 2009, 2012, 2020
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 (lp64/include/nag.h) has been created for the current NAG 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.
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.
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
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;}"
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.
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);
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);
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) ENDThis routine can be compiled and linked with the C files and NAG 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.
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
As Fortran stores multi-dimension arrays in column major order whereas C/C++ store in row major order, either
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.
At Mark 27, the nag_basic_types.h file provides the following variables which should be defined as required when compiling:
/* Define NAG_INTEGER64 if integer parameters use type long (Linux/Mac/Unix) or __int64 (Windows) #define NAG_INTEGER64 */ /* Define LONG_CHARLEN if string length parameters use type long (Linux/Mac/Unix) or __int64 (Windows) #define LONG_CHARLEN */ /* 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 */
The header file(s) as distributed should already have been modified appropriately for use with the version of the NAG library that you installed and the compiler it was generated with.
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.
For Windows implementations of the NAG Library, see the Users' Note for details of how to link C programs.
On most Unix-like systems linking can be achieved by using the 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_nagOn 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.
See the version of this file shipped as part of the product for links to the example programs listed below.
C05AWF Example Program
D03PCF Example Program
E04NFF Example Program
DGBTRS/F07BEF Example Program