使用Fortran 77子程序作为独立程序,从C++调用
Using Fortran 77 subprogram as stand-alone, calling from C++
所以我一直像躲避瘟疫一样躲避Fortran,但我的时间终于到了。。。我需要参与别人的Fortran代码(我们称之为程序A),并用它做两件事:
(1) 将它与第三方的Fortran代码(我们称之为程序B)合并,这样B就可以调用
(2) 将它与我的C++代码(程序C)合并,这样C就可以调用
B和C是优化算法,A是基准函数的集合。。。但在所有这些令人敬畏的事情发生之前,我必须首先编译A中我需要的部分。我需要的A的所有子程序都包含在一个文件中。我一直在根据我在网上得到的信息来调整它的形状(例如,在代码中添加"IMPLICIT NONE",并使其适合gfortran)。但我有两个顽固的bug和一个警告(我会把警告留到另一个帖子中)。
以下是我目前如何编译它(通过Makefile):
all:
gfortran progA.FOR
g++ -c progC.cpp
g++ -o Program.out progA.o progC.o
rm *.o
但第一行未能完成,出现以下错误,
第一个错误:
SUBROUTINE TP1(MODE)
1
Error: Unclassifiable statement at (1)
相关代码(从文件顶部开始):
IMPLICIT NONE
INTEGER NMAX,MMAX,LMAX,MNNMAX,LWA,LIWA,LACTIV,N,NILI,NINL,
/ NELI,NENL,NEX, MODE
PARAMETER (NMAX = 101,
/ MMAX = 50,
/ LMAX = 50,
/ MNNMAX = NMAX + NMAX + MMAX + 2,
/ LWA = 2*NMAX*NMAX + 33*NMAX + 10*MMAX + 200,
/ LIWA = MMAX + NMAX + 150,
/ LACTIV = 2*MMAX + 15)
LOGICAL INDEX1,INDEX2
SUBROUTINE TP1(MODE)
COMMON/L1/N,NILI,NINL,NELI,NENL
COMMON/L2/X(2)
COMMON/L4/GF(2)
COMMON/L6/FX
COMMON/L9/INDEX1
COMMON/L10/INDEX2
COMMON/L11/LXL
COMMON/L12/LXU
COMMON/L13/XL(2)
COMMON/L20/LEX,NEX,FEX,XEX(2)
REAL*8 X,G,GF,GG,FX,XL,XU,FEX,XEX
LOGICAL LXL(2),LXU(2),LEX
GOTO (1,2,3,4,4),MODE
1 N=2
NILI=0
NINL=0
NELI=0
NENL=0
X(1)=-2.D0
X(2)=1.D0
LXL(1)=.FALSE.
LXL(2)=.TRUE.
LXU(1)=.FALSE.
LXU(2)=.FALSE.
XL(2)=-1.5D0
LEX=.TRUE.
NEX=1
XEX(1)=1.D0
XEX(2)=1.D0
FEX=0.D0
RETURN
2 FX=100.D0*(X(2)-X(1)**2)**2+(1.D0-X(1))**2
RETURN
3 GF(2)=200.D0*(X(2)-X(1)**2)
GF(1)=-2.D0*(X(1)*(GF(2)-1.D0)+1.D0)
4 RETURN
END
我不明白为什么会出现这个错误,因为有300多个其他子程序以完全相同的方式声明(例如SUBROUTINE TP2(MODE)。。。,子程序TP300(模式))。
第二个错误:
HX=TP273A(X)
1
Error: Return type mismatch of function 'tp273a' at (1) (REAL(4)/REAL(8))
相关代码:
SUBROUTINE TP273(MODE)
COMMON/L1/N,NILI,NIML,NELI,NENL
COMMON/L2/X
COMMON/L4/GF
COMMON/L6/FX
COMMON/L11/LXL
COMMON/L12/LXU
COMMON/L20/LEX,NEX,FEX,XEX
LOGICAL LEX,LXL(6),LXU(6)
REAL*8 X(6),FX,GF(6),FEX,XEX(6),HX,DFLOAT
GOTO (1,2,3,4,4)MODE
1 N=6
NILI=0
NINL=0
NELI=0
NENL=0
DO 6 I=1,6
X(I)=0.D+0
XEX(I)=0.1D+1
LXL(I)=.FALSE.
6 LXU(I)=.FALSE.
LEX=.TRUE.
NEX=1
FEX=0.D+0
RETURN
2 HX=TP273A(X)
FX=0.1D+2*HX*(0.1D+1+HX)
RETURN
3 HX=TP273A(X)
DO 7 I=1,6
7 GF(I)=0.2D+2*(0.16D+2-DFLOAT(I))*(X(I)-0.1D+1)
1 *(0.1D+1+0.2D+1*HX)
4 RETURN
END
REAL*8 FUNCTION TP273A (X)
REAL*8 X(6),DFLOAT
TP273A=0
DO 10 I=1,6
10 TP273A=TP273A+(0.16D+2-DFLOAT(I))*(X(I)-0.1D+1)**2
RETURN
END
在阅读了物理学论坛之后,我尝试将变量"TP273A"重命名为"TP273Avar",这样它就不会与函数同名。这并没有解决错误。此外,我将"1"替换为"7GF(I)=…"下方的"F",并重新编译。一切都没有改变。我很确定我刚才提到的改变无论如何都是必要的,但肯定还有其他事情在发生
我也读过fortran中的数据类型不匹配和函数返回类型不匹配,所以我天真地尝试在文件的顶部添加"module mycode",在文件的底部添加"end module myode",但没有成功。
在这一切完成之后,我的目标是使用类似于的代码从C++调用这些子程序
#include <kitchensink>
extern"C"
{
void TP1_(int *mode);
}
int main()
{
TP1_(2);
return 0;
}
Fortran代码编译后,我想修改子例程,以便C++可以将std::vector X传递给TP#_(2,*X,*Y),并返回Y的计算值。我的std::vector X将替换每个子例程中的COMMON/L2 X,Y将是子例程中计算的FX的值。我使用了混合Fortran和C作为上述C++代码的指导。
至于B调用A部分,我希望它能像编译A和B一样简单,并在任何需要的地方添加"CALL TP1(MODE)"行。
任何指导都将不胜感激!!!
不能只在编译单元之外的文件中有语句。这些可以是子程序、函数、模块或程序。在您的例子中,您有一些语句(第一个是implicit none
),只有在它们之后才有子程序TP1的开始。
要么将过程组织在一个模块中,并将公共部分放在contains
部分之前(如果您是Fortran新手,则会有更多关于C++互操作性的工作),要么必须在每个子例程中分别包含implicit none
和其他部分。如果代码以前有效,你确定你甚至需要这个吗?
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 函数调用中参数的顺序重要吗
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在c++类上调用void函数
- 为什么 std::unique 不调用 std::sort?
- 调用专用模板时出错"no matching function for call to [...]"
- 选择要调用的构造函数
- C++为什么尽管我调用了void函数,它却不起作用
- 构造函数正在调用一个使用当前类类型的函数
- 变量没有改变?通过向量的函数调用
- 没有为自己的结构调用列表推回方法
- 调用'begin(int [n])'没有匹配函数
- 什么时候调用析构函数
- 如何用参数值调用函数(仅在运行时已知)
- std::cout.imbue()多重调用
- 函数何时会在c++中包含stack_Unwind_Resume调用