Как остановить подпрограмму и поднять флаг?

Я пишу программу на Fortran 95 (для компиляции с помощью gfortran), содержащую подпрограмму, выполняющую определенные вычисления. Как было предложено в "Fortran 95/2003 для ученых и инженеров" SJ Chapman, я пытаюсь остановить подпрограмму при обнаружении ошибки и "выбросить"[1] флаг ошибки, который "поймать "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 принимает целочисленное входное значение и итеративно делит его на значение, которое представляет собой входное значение, уменьшенное на число шагов-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++.


person Pier Paolo    schedule 07.08.2015    source источник
comment
Вы используете флаг ошибки в своем примере. Чего еще не сделаешь? У вас были проблемы с этим? Fortran ближе к C в этом отношении (C использует возвращаемые значения очень похожим образом).   -  person Vladimir F    schedule 07.08.2015
comment
Внутри подпрограммы вы должны использовать ту же логику, что и вызывающая программа — обернуть потенциально проблемный код внутри некоторой логики, чтобы без дальнейших церемоний перейти в конец подпрограммы при возникновении ошибки.   -  person High Performance Mark    schedule 07.08.2015
comment
@VladimirF: проблема не в приведенном выше псевдокоде, а в subroutine: скажем, у меня есть цикл, и я сталкиваюсь с делением на ноль. Я хотел бы поднять флаг до выполнения деления, не для выполнения деления и немедленного выхода из подпрограммы. Как я могу это сделать?   -  person Pier Paolo    schedule 07.08.2015
comment
Вы должны проверить значение делителя в условии if, установить возвращаемое значение и вернуться. Где вы видите проблему? Покажите пример фактического кода, который у вас есть.   -  person Vladimir F    schedule 07.08.2015
comment
@VladimirF: я добавил пример. Пожалуйста, посмотрите.   -  person Pier Paolo    schedule 07.08.2015
comment
@HighPerformanceMark: проблема в основном в том, что я не знаю, как остановить подпрограмму (как return, если хотите).   -  person Pier Paolo    schedule 07.08.2015


Ответы (2)


Глядя на ваш пример, кажется, что вам просто не хватает оператора 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
person Vladimir F    schedule 07.08.2015
comment
Нет, это нормально. Почему? Вы также можете иметь больше утверждений exit, что советует ерунда. По крайней мере, если применять вслепую. - person Vladimir F; 07.08.2015

Одной из возможностей было бы изменить

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

to

  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 выходит из цикла - ответ Владимира показывает вам, как использовать RETURN для более быстрого выхода из подпрограммы. Какой бы подход вы ни выбрали, не забудьте присвоить outval перед выходом из подпрограммы.

person High Performance Mark    schedule 07.08.2015