📄 c_and_f.htm
字号:
<DIV class=terminal><PRE>seaborg% <KBD> xlf90 -c f_main.f </KBD>
** f_calls_c === End of Compilation 1 ===
1501-510 Compilation successful for file f_main.f.
seaborg% <KBD>xlC -c calc_cwrapper.C</KBD>
seaborg% <KBD>xlC -o f_calls_c++ calc_cwrapper.o f_main.o -lm -lxlf90</KBD>
seaborg% <KBD>./f_calls_c++</KBD>
Inside C function, creating C++ object
Inside C++ constructor
The distance between the points is 5
Back in C function, will delete C++ object
Inside C++ destructor
</PRE></DIV>
<H3>Calling Fortran from C++</H3>
<P>You can call Fortran subroutines from C++ by declaring the routine </P><PRE> extern "C" void <VAR>fortran_routine_name</VAR>
</PRE>or for Fortran functions <PRE> extern "C" <VAR>return_type fortran_function_name</VAR>
</PRE>
<H2><A name=Calling_routines_in_Fortran_modules>Calling routines in Fortran
modules</A> </H2>
<P>To call routines from C that are defined in Fortran 90 modules, you must
refer to the Fortran <CODE>ROUTINE</CODE> as
<CODE>__modulename_NMOD_routine</CODE>. </P>
<P>For example, the Fortran routine: </P>
<DIV class=code><PRE>! FILENAME: calc_mod_f.f
!
MODULE CALCULATION
CONTAINS
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
END MODULE CALCULATION
</PRE></DIV>
<P>is called from the main C program in this way: </P>
<DIV class=code><PRE>
/* FILENAME: c_main_mod.c
Shows how to call a FORTRAN routine from C
In this case the FORTRAN routine, named CALC_DIST,
is in the FORTRAN module named calculation
*/
extern void __calculation_NMOD_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;
__calculation_NMOD_calc_dist(&p1_x,&p1_y,&p2_x,&p2_y);
}
</PRE></DIV>
<P>Compiling and running: </P>
<DIV class=terminal><PRE>seaborg% <KBD> xlf90 -c calc_mod_f.f </KBD>
** calculation === End of Compilation 1 ===
1501-510 Compilation successful for file calc_mod_f.f.
seaborg% <KBD>cc -o c_calls_f_mod c_main_mod.c calc_mod_f.o -lxlf90 -lm </KBD>
seaborg% <KBD>./c_calls_f_mod</KBD>
The distance between the points is 5.00000E+00
</PRE></DIV>
<H2><A name=characters>Working with characters</A> </H2>
<P>Passing characters and strings between Fortran and C is not straightforward.
When Fortran passes a CHARACTER string, it passes (by value) an extra argument
that contains the length of the string. In addition, C strings are usually
null-terminated, while Fortran character strings are not. </P>
<P>To pass a Fortran <TT>CHARACTER</TT> to a C routine that accepts a
<TT>char</TT>, the string must be null terminated. </P>
<P>The only character type in Fortran is CHARACTER, which is stored as a set of
contiguous bytes, one character per byte. The length is not stored as part of
the entity. Instead, it is passed by value as an extra argument at the end of
the declared argument list when the entity is passed as an argument. </P>
<P>If you are writing both parts of the mixed-language program, you can make the
C routines deal with the extra Fortran length argument, or you can suppress this
extra argument by passing the string using the %REF function. If you use %REF,
which you typically would for pre-existing C routines, you need to indicate
where the string ends by concatenating a null character to the end of each
character string that is passed to a C routine. </P>
<P>Following is an example that shows some correct and incorrect ways to pass
and handle characters and strings from Fortran to C. </P>
<DIV class=code><PRE>!FILENAME: give_chars.f
!
! Gives some examples of passing Fortran strings to
! a C routine that prints a character string beginning
! at the address of the start of the passed character
! string and ending at the C string termination character, which is
! CHAR(0) in Fortran.
PROGRAM give_chars
IMPLICIT NONE
CHARACTER(LEN=1):: a(9),d
CHARACTER(LEN=8):: b,c,e
REAL:: f
EXTERNAL TAKE_CHARS
! These are put in COMMON block to insure they are all
! adjacent in memory
COMMON//b,c,d
COMMON/c2/e,f
a(1) = 'a'
a(2) = 'b'
a(3) = 'c'
a(4) = 'd'
a(5) = 'e'
a(6) = 'f'
a(7) = 'g'
a(8) = 'h'
! This behavior of this call is undefined, since there is
! no string terminator character being passed to the C
! routine. It will 'work' if there fortuitously happens to be
! a zero in the next memory location after a(8).
PRINT *, ""
PRINT *, "This may or may not print a(1) to a(8):"
CALL TAKE_CHARS(a)
! This puts a string terminator character in a(6)
a(6) = CHAR(0) ! String terminator for C routine
PRINT *, ""
PRINT *, "This will print a(1) to a(5):"
CALL TAKE_CHARS(a)
!
b='ABCDEFGH'
c='ijklmnop'
d = CHAR(0) !String terminator for C routine
! The string terminator in d follows the string c in memory
! but there is no string terminator character between c and d
! (All this controlled by COMMON block declaration).
PRINT *, ""
PRINT *, "This will print string b and c:"
CALL TAKE_CHARS(b)
! Here we append a string terminator character to the
! string b when we pass it.
PRINT *, ""
PRINT *, "This will print string b only:"
CALL TAKE_CHARS(b // CHAR(0)) !Appends string terminator to b
! The following will print string e plus garbage
! because the C routine does not see a string terminator
! before the REAL value f
e = 'abcdefgh'
f = ATAN(1.)
PRINT *, ""
PRINT *, "This will print string e plus garbage:"
CALL TAKE_CHARS(e)
END PROGRAM give_chars
</PRE></DIV>
<P></P>
<DIV class=code><PRE>
/* FILENAME: take_chars.c
A routine to take a Fortran character string
and print it. It assumes that the Fortran routine
has explicitly appended a string terminator character
to the string before passing it.
*/
void take_chars(char *fstring, long int fstringLen)
{
/* This printf() function (with %s) will print characters until
it encounters a \0 character, which it interprets as an
end-of-string signal.
*/
printf("The passed string is: %s\n",fstring);
printf("The passed string length is: %d\n",fstringLen);
}
</PRE></DIV>
<P>Compile these routines with </P>
<DIV class=terminal><PRE>% <KBD> xlf90 -c give_chars.f</KBD>
% <KBD> cc -c take_chars.c </KBD>
% <KBD> xlf90 -o give_chars give_chars.o take_chars.o </KBD>
</PRE></DIV>
<P>When we run the program, we get: </P>
<DIV class=terminal><PRE>% <KBD> ./give_chars </KBD>
This may or may not print a(1) to a(8):
The passed string is: abcdefgh
The passed string length is: 1
This will print a(1) to a(5):
The passed string is: abcde
The passed string length is: 1
This will print string b and c:
The passed string is: ABCDEFGHijklmnop
The passed string length is: 8
This will print string b only:
The passed string is: ABCDEFGH
The passed string length is: 9
This will print string e plus garbage:
The passed string is: abcdefgh?IÛ
The passed string length is: 8
</PRE></DIV><A name=case></A>
<H2>Using mixed case names</H2>
<P>Sometimes you may want to link with code containing C/C++ routines that have
mixed-case or upper-case names. You can use these routines by using the
<TT>-U</TT> option when compiling with <TT>xlf</TT>. However, this makes all
functions, variables, and names case-sensitive. </P>
<P>You can also use the <TT>@PROCESS MIXED</TT> directive to declare case
sensitivity. For example: </P><PRE>@process mixed
external C_Func ! now we can call C_Func, not just c_func
integer aBc, ABC ! now these are two different variables
common /xYz/ aBc ! the same applies to common block names -
common /XYZ/ ABC ! these two are different
end
</PRE></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -