C/C++调用Fortran的使用说明

DreamsofJAVAD 2010-11-22

这里将详细介绍一下在C++中如何调用用Fortran语言编写函数的问题,即Fortran与C++的混合编程问题。

通常情况下,C++与Fortran的混合编程问题是利用动态链接库的方式进行的,换句话说,如果在C/C++中调用Fortran函数,应将Fortran函数按照一定的协议编译为动态链接库,然后即可实现二者的混合编程问题。实现这一目的有两种方式:显示链接与隐式链接,下面通过两个非常简单的实例分别介绍之。
编译环境:Fortran:推荐使用Compaq Visual Fortran 6.0以上的版本,C++:Microsoft Visual C++6.0。

1.   显式链接,
(a) 找开CVF编译器,然后新建一个Fortran DLL工程(选择Fortran Dynamic Link Library),并指定工程名,如下图所示:


按确定按钮,然后新建一个Fortran 源文件,并输入以下的Fortran代码:
(这里仅为说明问题,实际的问题比下面的代码要复杂得多。)
SUBROUTINE OUTPUT(N)

!必须声明本函数为输出函数:DLLEXPORT
!DEC$ ATTRIBUTES DLLEXPORT::OUTPUT  

IMPLICIT NONE
INTEGER N

N=N+10
WRITE(*,*) "N=",n
END SUBROUTINE OUTPUT

经编译,链接后,将在Debug目录下生成两个文件,即dll文件与lib文件。
(b) 启动Visual C++6.0,然后新建一个console工程(即Win32 Console Application,当然在MFC中也是完成可行的),如下图所示:


按确定按钮,新建一个空的工程后,再新建一个C++源文件,并输入以下的代码:
#include <iostream.h>
#include <windows.h>

int main()
{
typedef void (_stdcall * wndProc)(int& );
 
HINSTANCE hLibrary=LoadLibrary("pp.dll"); //加载动态库文件
if(hLibrary==NULL)
{
cout&lt;&lt;"can't find the dll file"&lt;&lt;endl;
return -1;
}

wndProc test=(wndProc)GetProcAddress(hLibrary,"OUTPUT"); //获得Fortran导出函数的地址
if(test==NULL)
{
cout&lt;&lt;"can't find the function file."&lt;&lt;endl;
return -2;
}

int n=3;
test(n); //调用fortran函数

FreeLibrary(hLibrary); //卸载动态库文件

return 0;
}
当编译通过后,将由fortran编译器生成的动态库文件(本算例为pp.dll)复制到C++的Debug文件夹中(即mm\debug),然后点击执行即可,程序的动行结果为:


2.   隐式链接
与上文所介绍的显示链接相比,隐式链接要相对容易一点。下面也通过一个算例进行说明。
(1) 建立一个Fortran动态库文件,其方法与上述完全相同,然后在CVF编译器中输入以下的代码:

SUBROUTINE OUTPUT(N)

!下面为对Fortran函数的声明
!ms$if .not. defined(LINKDIRECT)
!ms$attributes dllexport :: OUTPUT
!ms$endif 

IMPLICIT NONE
INTEGER N

N=N+10
WRITE(*,*) "N=",n
END SUBROUTINE OUTPUT

编译通过后,将在Fortran工程文件夹的Debug文件夹中生成两个文件,即*.dll文件与*.lib文件。
(2) 新建一个C++ Console项目,并新建一个C++文件,然后输入以下的代码:
#include &lt;iostream.h&gt;
#include &lt;windows.h&gt;

//声明函数OUTPUT为extern型的,即是从外部调用的。
extern "C" void _stdcall OUTPUT(int& n);

int main()
{
int n=3;
OUTPUT(n);

return 0;
}

然后将Fortran编译器生成的两个文件(dll文件与lib文件)复制到C++的当前目录下,并将lib文件加入到当前的C++工程项目中,如下图所示:
点击菜单“工程-添加工程-Files”,然后选中pp.lib文件即可,如下图所示:

此时即可通过编译,执行此程序,其输出结果如下所示:


总结
本文通过两个简单的实例详细介绍了如何在C++中调用Fortran函数的两种方法,即显式链接与隐式链接。当然实际中我们所遇到的问题将会比本实例要复杂得多,本文仅作为抛砖引玉之用。显式链接与隐式链接两种方法均各自有其优缺点,但由于隐式链接要比显示链接容易得多,也易于理解,实际的大部分算例均采用这种方式。


在linux中操作

对于通常的用户,接促C语言的较多,但是,C语言的开发者,有时还想利用高效的Fortran 数据包 或者是Fortran语言的开发者想借用C提供的强大辅助功能,为此,为了方便大家对二语言相互调用的学习。这里给出了一些简单的入门性技术介绍。
    1. C 调用Fortran
    编辑Fortran 源文件 add.f95
    subroutine add(a, b, c)
    implicit none
    real:: a, b, c
    !
    ! the add routine
    ! c = a+b
    !
    c = a + b
    write(*,*) a, ’+’, b, ’=’, c
    return
    end subroutine add
    这里部介绍Fortran的语法格式,add.f95的功能是建立一个add routine 也就是函数。
    编译 add.f95
    f95 -o add.o -c add.f95
    编辑C 主程序main.c
      1 #include <stdio.h>
      2
      3 extern void add_(float *a, float *b, float *c);
      4
      5 int main(int argc, char *argvs[])
      6 {
      7         float a, b, c;
      8         a = 5.0;
      9         b = 7.0;
     10         add_(&a, &b, &c);
     11
     12         return 0;
     13 }
    3: 声明你要调用的函数,这里注意,是add_,调用的时候用指针,即变量地址,你应该明白了Fortran的调用是改变参数值的。
    10:调用fortran函数
    编译与执行
    #gfortran -o main main.c add.o
    #./main
       5.000000     +   7.000000     =   12.00000
    NOTES; if you use the gcc tool, it will generate error
    #gcc -o main main.c add.o
    add.o: In function `add_’:
    add.f95:(.text+0x4c): undefined reference to `_gfortran_st_write’
    add.f95:(.text+0x69): undefined reference to `_gfortran_transfer_real’
    add.f95:(.text+0x87): undefined reference to `_gfortran_transfer_character’
    add.f95:(.text+0xa4): undefined reference to `_gfortran_transfer_real’
    add.f95:(.text+0xc2): undefined reference to `_gfortran_transfer_character’
    add.f95:(.text+0xdf): undefined reference to `_gfortran_transfer_real’
    add.f95:(.text+0xed): undefined reference to `_gfortran_st_write_done’
    collect2: ld returned 1 exit status
    Some Wrong with your PATH for you gcc library

    OK! you are clever and has known how call fortran routines in the C progaram. Next part I show you how to call C routines in the Fortran program!


    2, Fortran 调用 C 函数
    编辑C源码add.c
      1 #include <stdio.h>
      2
      3 void add_(float *a, float *b, float *c)
      4 {
      5         *c = *a + *b;
      6         printf(\"%f + %f = %f\\n\", *a, *b, *c);
      7 }
    Notes The funtion name \"add_\"
    编译源代码
    # gcc -o add.o -c add.c
    编辑fortran 主程序main.f95,编译和执行
      1 PROGRAM MAIN
      2   implicit none [Page]
      3   real:: i, j, k
      4   !
      5   ! The first fortran program
      6   !
      7   i = 5.0
      8   j = 8.0
      9   call add(i, j, k)
     10   stop
     11 end program MAIN
    NOTE 9 line
    # gfortran -o main main.f95 add.o (or f95 -o main main.f95 add.o)
    # ./main
    5.000000 + 8.000000 = 13.000000
 

OK. If you reach here, congratulations, you have learned how to call routines between C and fortran!

相关推荐

编程爱好者联盟 / 0评论 2017-03-19