C/C++调用Fortran的使用说明
C/C++調用Fortran的使用說明
| [日期:2010-11-22] | 來源:C/C++?作者:C/C++ | [字體:大 中 小] |
這里將詳細介紹一下在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<<"can't find the dll file"<<endl;
return -1;
}
wndProc test=(wndProc)GetProcAddress(hLibrary,"OUTPUT"); //獲得Fortran導出函數的地址
if(test==NULL)
{
cout<<"can't find the function file."<<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 <iostream.h>
#include <windows.h>
//聲明函數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!
例程:
Calling Fortran routines from C++
Example-1: Calling routines and functions
The following sample shows how Fortran routines and functions can be called from a C++ program.
(1) The C++ file:
//??? This illustrates how a Fortran routine and function may be
//??? called from a main program in C++
#include <iostream.h>
extern "C"
{
?????? void __stdcall FR1(int*,int *);
?????? int __stdcall FF1(int *);
}
int main()
{
?????? int n=10,nSq,nCube;
?????? FR1(&n,&nSq);
?????? cout << "The square is:" << nSq << endl;
?????? nCube=FF1(&n);
?????? cout << "The Cube is:" << nCube << endl;
?????? return 0;
}
(2) The Fortran file:
???????? SUBROUTINE FR1(N,M)
C?????? COMPUTES THE SQUARE OF N, RETURNS IN M????
???????? M=N*N
???????? RETURN
???????? END
C
???????? INTEGER FUNCTION FF1(N)
C?????? COMPUTES THE CUBE OF N
???????? FF1=N*N*N
???????? RETURN
???????? END
Back to Top
Example-2: Passing C char string to a Fortran routine
The following sample shows how a C char string may be passed from a C++ program to a Fortran routine.
(1) The C++ file:
//??? This illustrates how a Fortran routine may be
//??? called from a main program in C++, and a char[] string passed to it
#include <iostream.h>
#include <string.h>
extern "C"
{
?????? void __stdcall FR1(int *,int *,char *);
}
int main()
{
???? int n=10,nSq;
char szCtest[20];
strcpy(szCtest,"teststring");
FR1(&n,&nSq,szCtest);
cout << "The square is:" << nSq << endl;
???????? return 0;
}
(2) The Fortran file:
???????? SUBROUTINE FR1(N,M,CSTR)
INTEGER*4 CSTR(1)
C?????? HERE WE RECEIVE THE C CHAR STRING IN AN INTEGER ARRAY
C?????? COULD ALSO HAVE USED A BYTE ARRAY
M=N*N
WRITE(6,20) (CSTR(L),L=1,3)
???? 20??? formAT(' CSTR=',3A4)
???????? WRITE(6,*) 'DONE'
RETURN
END
Back to Top
Example-3: Passing arrays to a Fortran routine
The following sample shows how arrays may be passed from a C++ program to a Fortran routine.
(1) The C++ file:
??? // Illustrate passing integer and floating point arrays
??? // from C++ to Fortran
??? #include <iostream.h>
??? extern "C"
??? {
??????? int __stdcall SUMIT(int *,int*);
??????? float __stdcall MEAN(float*,int*);
??? }
??? int main()
??? {
??????? int iA[]={3,5,6,7,2,3,4,5,11,7},iN=10,iSum;
??????? float fpA[]={1.2f,3.f,44.f,2.5f,-1.3f,33.44f,5.f,0.3f,-3.6f,24.1f},fpMean;
??????? iSum=SUMIT(iA,&iN);
??????? cout << "The Sum of iA is:" << iSum << endl;
??????? fpMean=MEAN(fpA,&iN);
??????? cout << "The Mean of fpA is:" << fpMean << endl;
??????? return 0;
??? }
(2) The Fortran file:
?????? INTEGER FUNCTION SUMIT(IA,N)
?????? INTEGER IA(1)
?????? ISUM=0
?????? DO 50 J=1,N
50??? ISUM=ISUM+IA(J)
?????? SUMIT=ISUM
?????? RETURN
?????? END
C
?????? REAL FUNCTION MEAN(RA,N)
?????? REAL RA(1)
?????? SUM=0.
?????? DO 50 J=1,N
50??? SUM=SUM+RA(J)
?????? IF(N.GT.0) MEAN=SUM/FLOAT(N)
?????? RETURN
?????? END
Back to Top
Calling C++ routines from Fortran
The following examples work with Microsoft Visual C++ and Compaq Visual Fortran. Your mileage may vary on other systems.
Example-1: Calling routines and functions
The following sample shows how C++ routines and functions can be called from a Fortran program.
(1) The Fortran file:
?????? INTEGER CR2
?????? N=10
?????? CALL CR1(N,M)
?????? WRITE(6,20) N,M
20??? formAT(' The square of',I3,' is',I4)
?????? K=CR2(N)
?????? WRITE(6,30) N,K
30??? formAT(' The cube of',I3,' is',I15)
?????? CALL EXIT
?????? END
(2) The C++ files:
?????? extern "C"
?????? {
void __stdcall CR1(int *,int *);
int __stdcall CR2(int *);
?????? }
?????? void __stdcall CR1(int *n, int *m)
?????? {
// Compute the square of n, return in m
int k;
k=*n;
*m=k*k;
return;
?????? }
?????? int __stdcall CR2(int *n)
?????? //??? Compute the cube of n
?????? {
???????? int m,k;
k=*n;
???????? m=k*k*k;
return m;
?????? }
Back to Top
Further Reading
These are some other sources of information.
Digital Visual Fortran Programmer's Guide, esp. the chapter titled "Programming with Mixed Languages". This online book is included with all recent versions of the compiler. The book is also available for download in PDF format by clicking here.
Mixed-Language Issues (from Microsoft)
Also see Microsoft's C Calls to Fortran page.
Mixed Language Programming using C++ and Fortran 77 by Carsten A. Arnholm has many examples.
Mixed Language Programming - Fortran and C by Allan, Chipperfield and Warren-Smith is another good source.
FTN95 Mixed Language Programming from the University of Salford.
A Comparison of C++, Fortran 90 and Oberon-2 for Scientific Programming by Bernd M?sli.
Interfacing Fortran and C by Janne Saarela.
Mixed Language Programming from Pittsburgh Supercomputing Center.
Some examples from DEC:
Visual C/C++ Calling Visual Fortran DLL Example
Visual Fortran Calling Visual C Example
Visual Basic - Visual Fortran DLL Example
Will C++ be faster than Fortran? by T.L.Veldhuizen and M.E.Jernigan.
Interfacing Absoft Fortran with C.
Mixing ANSI-C with Fortran 77 or Fortran 90 by B. Einarsson.
Comparison of C++ and Fortran 90 for Object Oriented Scientific Programming by J.Cary, S.Shasharina, J.Cummings, J.Reynders and P.Hinker.
Fortran and C Programming from Iowa State University.
Win32 Fortran Compiler Comparisons by John Appleyard.
Calling Fortran Routines from C/C++ by J. Thornburg.
f2c - Fortran to C Converter
------------------------------file:a.cpp-------------
#include <iostream.h>
#include <math.h>
extern "C"
{
void _stdcall TESTA(int *);
}
void main()
{
???? double?? a = sin(1.00);
???? cout<<"a="<<a;
???? int ii=1;
???? TESTA(&ii);
}
------------------------------file:b.f-------------
SUBROUTINE TESTA(IA)
WRITE(*,*) "IA=", IA
RETURN
END
編譯提示錯誤:
Linking...
dfor.lib(matherr.obj) : error LNK2005: __matherr already defined in LIBCD.lib(matherr.obj)
LINK : warning LNK4098: defaultlib "libc.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
Debug/StaggeredGrid.exe : fatal error LNK1169: one or more multiply defined symbols found
Error executing link.exe.
經過分析發現是因為在main函數里面調用了sin數學函數,解決的方法是添加文件頭:
#pragma comment (lib, "dfor")
總結
以上是生活随笔為你收集整理的C/C++调用Fortran的使用说明的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux下动态链接库调用
- 下一篇: 年后开课 | 第 4 期临床基因组家系分