【问题标题】:How to stop a subroutine and raise a flag?如何停止子程序并引发标志?
【发布时间】:2025-12-15 21:05:02
【问题描述】:

我正在用 Fortran 95 编写一个程序(使用 gfortran 编译),其中包含一个执行特定计算的子例程。正如 S. J. Chapman 在“Fortran 95/2003 for Scientists & Engineers”中所建议的那样,我试图在遇到错误时停止子例程并“抛出”[1] 一个错误标志,即“catch "ed[1] 由调用程序执行,它将执行所有必要的操作。理想情况下,我会这样做:

! Pseudo-code
PROGRAM my_prog
    integer :: error_flag
    CALL my_subr (<input_args>, <output_args>, error_flag)
    ! Also error_flag is an output: 0 -> everything OK, 1 -> error
    IF (error_flag /= 0) THEN
        WRITE (*,*) 'Error during execution of "my_subr"'
    ELSE
        ... do something ...
    END IF
END PROGRAM my_prog

如何停止子程序并优雅地处理错误?

这里是一个例子:subroutine“除法”接受一个整数输入值并迭代地将它除以一个值,该值是输入值减去 step-1 的数量。当这个值达到零时,应该引发一个标志并且应该退出子程序而不执行除以零。

SUBROUTINE division (inval, outval, error_flag)
  IMPLICIT NONE

  INTEGER, INTENT(IN) :: inval
  REAL, INTENT(OUT) :: outval
  INTEGER, INTENT(OUT) :: error_flag ! 0 -> OK, 1 -> error

  INTEGER :: i
  REAL :: x

  error_flag = 0
  x = REAL(inval)
  DO i = 0, 10
     IF (inval-i == 0) error_flag = 1
     ! How can I gracefully exit now?
     x = x / REAL(inval-i)
  END DO

END SUBROUTINE division

PROGRAM my_prog
  IMPLICIT NONE
  REAL :: outval
  INTEGER :: error_flag
  CALL division (8, outval, error_flag)
  IF (error_flag == 1) THEN
     WRITE (*,*) 'Division by zero'
  ELSE
     WRITE (*,*) 'Output value:', outval
  END IF
END PROGRAM my_prog

注意事项:

[1] 我在借用(以一种可能不恰当的方式)C++ 的行话。

【问题讨论】:

  • 您在示例中使用了错误标志。还有什么你不会的?你有问题吗? Fortran 在这方面更接近于 C(C 使用返回值的方式非常相似)。
  • @VladimirF:问题不在于上面的伪代码,而在于subroutine:假设我有一个循环,我遇到了一个被零除的问题。我想提出一个标志之前执行除法,执行除法并立即“退出”子程序。我该怎么做?
  • 必须在if条件中检查除数的值,设置返回值并返回。你在哪里看到问题?显示您拥有的实际代码的示例。
  • @VladimirF:我添加了一个示例。请看一看。

标签: fortran gfortran subroutine


【解决方案1】:

看到您的示例,您似乎只是缺少return 声明:

  error_flag = 0
  x = REAL(inval)
  DO i = 0, 10
     IF (inval-i == 0) then
                         error_flag = 1
                         return
     END IF

     x = x / REAL(inval-i)
  END DO

【讨论】:

  • 不,没关系。为什么?你也可以有更多的exit 声明,这个建议是无稽之谈。至少在盲目应用的情况下。
【解决方案2】:

一种可能性是改变

  DO i = 0, 10
     IF (inval-i == 0) error_flag = 1
     ! How can I gracefully exit now?
     x = x / REAL(inval-i)
  END DO

  DO i = 0, 10
     IF (inval-i == 0) THEN 
        error_flag = 1
        EXIT
     END IF
     ! Now you have gracefully exited
     x = x / REAL(inval-i)
  END DO
  ! Code to tidy up if the error flag was set

这里EXIT 语句退出循环——Vladimir 的回答向您展示了如何使用RETURN 更立即地退出子例程。无论您选择哪种方法,都不要忘记在离开子例程之前分配给outval

【讨论】: