【问题标题】:Using Fortran 77 subprogram as stand-alone, calling from C++使用 Fortran 77 子程序作为独立程序,从 C++ 调用
【发布时间】:2013-08-19 18:28:14
【问题描述】:

所以我一直像瘟疫一样避免 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

阅读Physics Forums 后,我尝试将变量“TP273A”重命名为“TP273Avar”,这样它就不会与函数同名。这没有解决错误。此外,我将“1”替换为“7 GF(I) = ...”下方的“F”并重新编译。没有改变。我很确定我刚才提到的更改无论如何都是必要的,但肯定还有其他事情发生。

我也看过Data type mismatch in fortranFunction return type mismatch,所以我天真地尝试在文件顶部添加“module mycode”,在文件底部添加“end module 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 值。我使用Mixing Fortran and C 作为上述 C++ 代码的指导。

至于B调用A部分,我希望它就像编译A和B一样简单,并在我需要的地方添加“CALL TP1(MODE)”行。

任何和所有的指导将不胜感激!!!

【问题讨论】:

  • 不直接回答你的问题,但是:Fortran 不是瘟疫,它只是一种语言,与 C++ 相比是一种简单的语言。如果你需要修改 Fortran 代码,我强烈建议你先学一点:here 是 Fortran 77 的一个很好的介绍,here 是 Fortran 77 标准(Fortran 77 不是可用的最新版本,但您似乎在这里使用它)。
  • 你是对的。只是我 90% 的 Fortran 经验都涉及我认为写得不好的代码,所以每次有人说“这里有一些 Fortran 代码供你使用”时,我都会不寒而栗。
  • 我不同意@arbautjc,尽管我的工作涉及到很多 Fortran。 Fortran 95/2003 很好(有时比 C 更容易),但我避免像瘟疫一样使用 Fortran 77!我见过写得很好的 Fortran 77 例程,但它们很少见。

标签: c++ compiler-errors fortran


【解决方案1】:

您不能只在编译单元之外的文件中包含语句。这些可以是子程序、函数、模块或程序。在您的情况下,您有一些语句(其中第一个是 implicit none),只有在它们之后才有子例程 TP1 的开始。

要么在一个模块中组织过程并将公共部分留在contains 部分之前(如果您是 Fortran 新手,将进行更多关于 C++ 互操作性的工作)或者您必须在每个子例程中包含 implicit none 和其他分别地。如果代码以前有效,你确定你甚至需要这个吗?

【讨论】:

  • 感谢您的回复。我是 Fortran 新手。按照建议,我将程序包装在: MODULE herp { IMPLICIT NONE 并以 INDEX2 } CONTAINS { 其余部分,以 SUBROUTINE TP1(MODE)...} END MODULE herp (为了清楚起见)。现在,尽管“模式”列在模块内的整数声明中,但我收到 25 多个错误,说“符号'模式'没有隐式类型”。对于任何其他变量似乎都没有这样做(但编译器在 25 个错误后放弃了)。至于你的问题:这段代码在我无法与 B 或 C 合并的更大程序的上下文中工作。你的想法?
  • 如果您看到我在此回复中标记了您,请告诉我。我也在学习如何使用 Stackoverflow 的功能 :)
  • 由于MODE 是子程序的虚拟参数(又名参数),因此必须在其中声明。无论您在上层(即模块)范围内用相同的名称声明什么,它都会被隐藏并且在子例程内无法访问。顺便说一句,用户的任何答案都会出现在他们的收件箱中,不用担心。
  • 我想补充一点,您的第二个问题可以通过将 TP273A 放入一个模块并从那里使用它来解决。问题是,第一次遇到 TP273A,它的类型还没有声明,所以它自动声明为单精度实数!这是因为如果您忘记了声明,Fortran 会为您选择一个类型。为防止这种情况发生,请将implicit none 放在每个模块的开头,以及模块外的每个函数或子例程。使用implicit none 是 Fortran 101 中的安全编程。编辑:不小心按 Enter 太早了。
  • 或者,您可以在TP273 的顶部声明REAL*8 TP273A,它声明了函数的返回类型,并且比使用模块稍快。但是,如果您长时间使用 Fortran,则绝对应该学习使用模块。
猜你喜欢
  • 1970-01-01
  • 2015-08-08
  • 2015-11-19
  • 1970-01-01
  • 2012-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-14
相关资源
最近更新 更多