📄 c_and_f.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0063)http://www.nersc.gov/nusers/resources/software/ibm/c_and_f.html -->
<HTML><HEAD>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META content="MSHTML 6.00.2900.3086" name=GENERATOR></HEAD>
<BODY style="BACKGROUND-COLOR: white"><!-- BEGIN PAGE CONTENT -->[an error
occurred while processing this directive]
<H1>Mixing C and Fortran on the SP</H1>
<P>Routines written in Fortran and C/C++ can be mixed in a single program. The
xlf compiling system assumes that C/C++ routine names are all lower case.
Following this convention will make compiling and linking easier. </P>
<P>Care must be taken with data types that are passed to the subroutines. Here
is a table showing corresponding datatypes. </P>
<TABLE class=ntable>
<TBODY>
<TR>
<TH>FORTRAN</TH>
<TH>C/C++</TH>
<TH>Bytes</TH></TR>
<TR>
<TD><TT>REAL,REAL*4,REAL(KIND=4)</TT></TD>
<TD><TT>float</TT></TD>
<TD><TT>4</TT></TD></TR>
<TR>
<TD><TT>REAL*8,REAL(KIND=8),DOUBLE PRECISION</TT></TD>
<TD><TT>double, long double</TT></TD>
<TD><TT>8</TT></TD></TR>
<TR>
<TD><TT>REAL*16,REAL(KIND=16)</TT></TD>
<TD><TT>long double (with -qlongdouble or -qldbl128)</TT></TD>
<TD><TT>16</TT></TD></TR>
<TR>
<TD><TT>INTEGER, INTEGER*4, INTEGER(KIND=4)</TT></TD>
<TD><TT>int, long int</TT></TD>
<TD><TT>4</TT></TD></TR>
<TR>
<TD><TT>INTEGER*8, INTEGER(KIND=8)</TT></TD>
<TD><TT>long long int</TT></TD>
<TD><TT>8</TT></TD></TR>
<TR>
<TD><TT>INTEGER*2</TT></TD>
<TD><TT>short int</TT></TD>
<TD><TT>2</TT></TD></TR>
<TR>
<TD><TT>COMPLEX, COMPLEX*4</TT></TD>
<TD><TT>structure of two floats</TT></TD>
<TD><TT>8</TT></TD></TR>
<TR>
<TD><TT>COMPLEX*8</TT></TD>
<TD><TT>structure of two doubles</TT></TD>
<TD><TT>16</TT></TD></TR>
<TR>
<TD><TT>DOUBLE COMPLEX, COMPLEX*16</TT></TD>
<TD><TT>structure of two long doubles</TT></TD>
<TD><TT>32</TT></TD></TR>
<TR>
<TD><TT>CHARACTER</TT></TD>
<TD>See <A
href="http://www.nersc.gov/nusers/resources/software/ibm/c_and_f.html#characters">Working
with characters</A> below.</TD>
<TD> </TD></TR></TBODY></TABLE>
<P>The subsections of this topic are </P>
<UL>
<LI><A
href="http://www.nersc.gov/nusers/resources/software/ibm/c_and_f.html#Calling_C_from_Fortran">Calling
C from Fortran</A>
<LI><A
href="http://www.nersc.gov/nusers/resources/software/ibm/c_and_f.html#Calling_Fortran_from_C">Calling
Fortran from C</A>
<LI><A
href="http://www.nersc.gov/nusers/resources/software/ibm/c_and_f.html#Cpp">Mixing
Fortran and C++</A>
<LI><A
href="http://www.nersc.gov/nusers/resources/software/ibm/c_and_f.html#Calling_routines_in_Fortran_modules">Calling
routines in Fortran modules</A>
<LI><A
href="http://www.nersc.gov/nusers/resources/software/ibm/c_and_f.html#characters">Working
with characters</A>
<LI><A
href="http://www.nersc.gov/nusers/resources/software/ibm/c_and_f.html#case">Using
Mixed Case Names</A> </LI></UL>
<P>For further information beyond that found on this page, see The XL Fortran
User's Guide, chapter 10, <A
href="http://hpcf.nersc.gov/vendor_docs/ibm/xlf/html/UG74.HTM#HDRILC">"Interlanguage
Calls."</A> </P>
<H2><A name=Calling_C_from_Fortran>Calling C from Fortran</A> </H2>
<P>As long as you keep in mind how the variable types correspond to each other
in Fortran and C as shown in the table above, calling a C routine from Fortran
is straightforward as long as the name of the C routine is all lowercase. </P>
<P>Fortran passes addresses in subroutines calls, so the C routine should accept
a pointer to the proper data type. </P>
<P>Below is a simple example. First, the Fortran main program: </P>
<DIV class=code><PRE>!FILENAME: f_main.f
!
PROGRAM f_calls_c
IMPLICIT NONE
REAL :: p1_x, p1_y, p2_x, p2_y
EXTERNAL calc_dist
p1_x = 0.0
p1_y = 0.0
p2_x = 3.0
p2_y = 4.0
CALL calc_dist(p1_x,p1_y,p2_x,p2_y)
END PROGRAM f_calls_c
</PRE></DIV>
<P>And the C routine: </P>
<DIV class=code><PRE>/* FILENAME: calc_c.c
*/
#include <math.h>
void calc_dist(float *x1, float *y1, float *x2, float *y2)
{
float dxsq, dysq, distance;
dxsq = (*x2-*x1)*(*x2-*x1);
dysq = (*y2-*y1)*(*y2-*y1);
distance = sqrt( dxsq + dysq );
printf("The distance between the points is %13.5e\n",
distance);
}
</PRE></DIV>
<P>Compiling and executing: </P>
<DIV class=terminal><PRE>seaborg% <KBD> cc -c calc_c.c </KBD>
seaborg% <KBD> xlf90 -o f_calls_c f_main.f calc_c.o </KBD>
** f_calls_c === End of Compilation 1 ===
1501-510 Compilation successful for file f_main.f.
seaborg% <KBD> ./f_calls_c </KBD>
The distance between the points is 5.00000e+00
</PRE></DIV>
<H2><A name=Calling_Fortran_from_C>Calling Fortran from C</A> </H2>
<P>Calling a Fortran routine from C is similar. Here are the same two routines
as shown above, but with the languages switched for each file. </P>
<DIV class=code><PRE>/* FILENAME: c_main.c
Shows how to call a FORTRAN routine from C
*/
extern void calc_dist(float*, float*, float*, float*);
void main()
{
float p1_x,p1_y,p2_x,p2_y;
p1_x = 0.0;
p1_y = 0.0;
p2_x = 3.0;
p2_y = 4.0;
calc_dist(&p1_x,&p1_y,&p2_x,&p2_y);
}
</PRE></DIV>
<P></P>
<DIV class=code><PRE>! FILENAME: calc_f.f
!
SUBROUTINE calc_dist(x1,y1,x2,y2)
IMPLICIT NONE
REAL :: x1,y1,x2,y2
REAL :: distance
distance = SQRT( (x2-x1)**2 + (y2-y1)**2 )
WRITE(6,1) distance
1 FORMAT("The distance between the points is ", 1pe13.5)
END SUBROUTINE calc_dist
</PRE></DIV>
<P></P>
<DIV class=terminal><PRE>seaborg% <KBD> xlf90 -c calc_f.f </KBD>
** calc_dist === End of Compilation 1 ===
1501-510 Compilation successful for file calc_f.f.
seaborg% <KBD> cc -o c_calls_f c_main.c calc_f.o -lxlf90 -lm</KBD>
seaborg% <KBD> ./c_calls_f </KBD>
The distance between the points is 5.00000E+00
</PRE></DIV>
<P>Note that we had to explicitly link with <TT>-lxlf90 -lm</TT> when using cc.
</P>
<H2><A name=Cpp>Mixing Fortran and C++</A> </H2>
<P>In order to mix Fortran and all C++ functions, you must pass the
interlanguage calls through C "wrapper" functions. This is because the C++
compiler "mangles" the names of some C++ functions. C++ functions that are
declared and used like regular C functions can be called just like C functions,
however. </P>
<P>In addition, you must use the xlC command to perform the final linkage step.
</P>
<P>Here's C++ code that performs the same task as does the C function above that
calculates the distance between points. </P>
<DIV class=code><PRE>/* FILENAME: calc_c++.h
This is the C++ routine.
*/
#include <iostream.h>
#include <math.h>
template<class T> class calc {
public:
calc() {cout <<"Inside C++ constructor"<<endl;}
~calc() {cout <<"Inside C++ destructor"<<endl;}
void calc_dist(T *x1, T *y1, T *x2, T *y2)
{
T dxsq, dysq, distance;
dxsq = (*x2-*x1)*(*x2-*x1);
dysq = (*y2-*y1)*(*y2-*y1);
distance = sqrt( dxsq + dysq );
cout <<"The distance between the points is "
<<distance<<" \n"<<endl;
}
};
</PRE></DIV>
<P>In order to call this routine safely from Fortran, you must "wrap" the
function with a C-style function, something like this: </P>
<DIV class=code><PRE>/* Filename: calc_cwrapper.C */
#include <stdio.h>
#include "calc_c++.h"
extern "C" void calc_dist(float *x,float *y,float *X,float *Y);
void calc_dist(float *x,float *y,float *X,float *Y) {
printf("Inside C function, creating C++ object\n");
calc<float>* c=new calc<float>();
c->calc_dist(x,y,X,Y);
printf("Back in C function, will delete C++ object\n");
delete c;
}
</PRE></DIV>
<P>Compiling and running (using f_main.f): </P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -