Calling NAG Fortran Library Routines from C Language Programs
Using the NAG C Header Files on
Unix Systems
Ian Hounam
NAG Ltd, Oxford
© The Numerical Algorithms Group Ltd, Oxford UK. 2002
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 and the current NAG Graphics 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. Note that if __STDC__ is not defined, no argument checking will be carried out.
DOUBLE PRECISION D double d;
INTEGER I int i;
LOGICAL L int l;
CHARACTER*n S char s[n];
DOUBLE COMPLEX Z struct {double re,im;} z;
All 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.
As Fortran stores multi-dimension arrays in column major order whereas C stores in row major order, either
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 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"};
int len_c = 5;
nagsub_(&a, b, (char *)c, len_a, len_b, 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 HP-UX 64 bit compiler uses long instead of int for the hidden length argument.
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;}"
Procedure arguments, i.e. function or subroutine names, are passed by address in the normal C manner.
DOUBLE COMPLEX FUNCTION F(X)
DOUBLE COMPLEX X
has the following prototype:
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);
Note that the NAGWare compiler has an option to use the de facto standard described above, but this is not used in the NAG Fortran Library implementations.
The prototype for the user supplied function F with HP-UX or NAGWare is the following.
Complex (*f)(Complex *)and a user callable function, e.g S01EAF, looks like this
extern Complex s01eaf_(const Complex *z,int *ifail);
One solution is to use the NAGWare Compiler implementation of the NAG Fortran Library, see above.
As it is impossible to access the return value of a DOUBLE COMPLEX FUNCTION from C, another solution is to write a Fortran "jacket" routine to convert the DOUBLE COMPLEX 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)
DOUBLE COMPLEX 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 files do not contain prototypes for these jacket functions. Use the "Standard Unix" version of the C Header File on these systems and modify the 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 HP-UX 64 bit compiler uses long instead of int for the hidden length argument.
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 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 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 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 fun(double p[], int *tdp);
nagsub_(fun);
}
Example 2 below shows a complete example program that illustrates
these concepts.
#ifdef __cplusplus
extern "C" {
#endif
(with a matching "}" at the end of the file)
| Platform | Underscore | Complex Functions |
| All NAGWare f95 Implementations | Yes | Complex Functions |
| DEC Alpha Unix | Yes | Standard Unix plus jacket |
| HP9000/700 32 bit implementation | Both | Complex Functions |
| HP9000/700 64 bit implementation | Yes | Use specific HP64 Header File |
| IBM AIX | No | Standard Unix plus jacket |
| Silicon Graphics | Yes | Standard Unix plus jacket |
| Sun Solaris 32 bit implementation | Yes | Standard Unix |
| Sun Solaris 64 bit implementation | Yes | Complex Functions |
Note: "Both" in the "Underscore" column means that the NAG Fortran Library is supplied in two forms; with and without underscores. Use the C Header File appropriate to the library installed on your system.
The graphics library does not contain the complex data type, so the only issue is whether routine names have an underscore or not. For platforms with "Both" in the "Underscore" column above, please refer to local documentation (or failing this trial and error may be used) to find the correct convention for your graphics library.
cc -c myprog.c f77 -o myprog myprog.o -lnagOn 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 load command. The libraries may be documented in the f77 man page or, failing that, the commands generated by the compiler driver may be viewed using the -v, -dryrun or -# options to display the ld command line.