[英]Using Fortran 77 subprogram as stand-alone, calling from C++
因此,我一直像瘟疫一样避开Fortran,但最终我的时机到了……我需要参加别人的Fortran代码(我们称之为程序A),并用它做两件事:
(1)将其与第三方的Fortran代码合并(我们将其称为程序B),以便B可以调用A
(2)将其与我的C ++代码(程序C)合并,以便C可以调用A
B和C是优化算法,而A是基准函数的集合...但是,在所有令人惊奇的事情发生之前,我必须首先编译所需的A部分。 我需要的所有A子例程都包含在一个文件中。 我一直在根据在线信息(例如,在代码中添加“ IMPLICIT NONE”并使其适合gfortran)来使其成形。 但是我有两个顽固的错误和一个警告(我将警告留在另一篇文章中)。
这是我当前(通过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),...,SUBROUTINE TP300(MODE))。
第二次错误:
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”替换为“ 7 GF(I)= ...”下方的“ F”并重新编译。 没有改变。 我很确定我刚才提到的更改仍然是必需的,但是还必须进行其他操作。
我也阅读了fortran中的数据类型不匹配和函数返回类型不匹配 ,因此我天真地尝试将“模块mycode”添加到文件的顶部,将“结束模块mycode”添加到文件的底部无济于事。
说完这些之后,我的目标是使用类似于以下的代码从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
和other。 如果代码以前可以工作,您确定甚至需要此吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.