Сохраняет ли Fortran значение внутренних переменных посредством вызовов функций и подпрограмм?

после очень болезненной отладки я считаю, что нашел уникальное свойство Fortran, которое я хотел бы проверить здесь, в stackoverflow.

Я заметил, что, по крайней мере, значение внутренних логических переменных сохраняется при вызовах функций или подпрограмм.

вот пример кода, иллюстрирующий мою точку зрения:

PROGRAM function_variable_preserve
IMPLICIT NONE

CHARACTER(len=8) :: func_negative_or_not ! Declares function name
INTEGER :: input
CHARACTER(len=8) :: output

input = -9

output = func_negative_or_not(input)
WRITE(*,10) input, " is ", output
10 FORMAT("FUNCTION: ", I2, 2A)

CALL sub_negative_or_not(input, output)
WRITE(*,20) input, " is ", output
20 FORMAT("SUBROUTINE: ", I2, 2A)

WRITE(*,*) 'Expected negative.'


input = 7
output = func_negative_or_not(output)
WRITE(*,10) input, " is ", output

CALL sub_negative_or_not(input, output)
WRITE(*,20) input, " is ", output

WRITE(*,*) 'Expected positive.'

END PROGRAM function_variable_preserve

CHARACTER(len=*) FUNCTION func_negative_or_not(input)
IMPLICIT NONE

INTEGER, INTENT(IN) :: input
LOGICAL :: negative = .FALSE.

IF (input < 0) THEN
    negative = .TRUE.
END IF

IF (negative) THEN
    func_negative_or_not = 'negative'
ELSE 
    func_negative_or_not = 'positive'
END IF

END FUNCTION func_negative_or_not

SUBROUTINE sub_negative_or_not(input, output)
IMPLICIT NONE

INTEGER, INTENT(IN) :: input
CHARACTER(len=*), INTENT(OUT) :: output
LOGICAL :: negative = .FALSE.

IF (input < 0) THEN
    negative = .TRUE.
END IF

IF (negative) THEN
    output = 'negative'
ELSE 
    output = 'positive'
END IF

END SUBROUTINE sub_negative_or_not

это выход:

FUNCTION: -9 is negative
SUBROUTINE: -9 is negative
 Expected negative.
FUNCTION:  7 is negative
SUBROUTINE:  7 is negative
 Expected positive.

как вы можете видеть, кажется, что после функции или подпрограмма вызывается один раз, логическая переменная negative, Если перешли к .TRUE., остается как таковой, несмотря на инициализацию negative to .FALSE. в операторе объявления типа.

Я могу, конечно, исправить эту проблему, просто добавив строку негативный. = ЛОЖНЫЙ. после объявления переменной в моей функции и подпрограмме.

для переносимости и повторного использования кода, не должен ли язык (или компилятор) требовать повторной инициализации всех внутренних переменных при каждом вызове подпрограммы или функции?

3 ответов


чтобы ответить на ваш вопрос:да Fortran сохраняет значение внутренних переменных через вызовы функций и подпрограмм.

при определенных условиях ...

Если вы объявляете внутреннюю переменную с атрибутом SAVE, ее значение сохраняется из одного вызова в другой. Это, конечно, полезно в некоторых случаях.

однако ваш вопрос является общей реакцией при первом изучении одного из gotchas Фортрана: если вы инициализируете внутренняя переменная в своем объявлении автоматически приобретает атрибут SAVE. Вы сделали именно это в своих подпрограммах. Это стандарте. Если вы не хотите, чтобы это произошло не инициализируется в декларации.

Это является причиной большого удивления и жалобы от (некоторых) новичков на язык. Но независимо от того, как сильно они жалуются, это не изменится, поэтому вам просто нужно (а) знать об этом и (Б) программировать в осознании этого.


это не слишком отличается от static переменные с областью действия в C или c++.

язык программирования дизайн был в зачаточном состоянии, когда FORTRAN был развитый. Если он был разработан с нуля, сегодня, без сомнения, многие конструкции решения были бы другими.

изначально FORTRAN даже не поддерживал рекурсию, не было динамической памяти распределение, программы играли во всевозможные игры типа каламбура с COMMON блоки и EQUIVALENCE заявления, процедуры могут иметь несколько точек входа....так модель памяти была в основном для компилятора / компоновщика, чтобы выложить все, даже локальное переменные и числовые литеральные константы, в фиксированные места хранения, а не на стек. Если вы хотите, вы даже можете написать код, который изменил значение " 2 " на "42"!

к настоящему времени, есть очень много наследия FORTRAN код там, и авторы компиляторов идут на многое, чтобы сохранить обратно совместимую семантику. Я не могу процитировать главу и стих из стандарта, который предписывает поведение, которое вы отметили, или его обоснование, но кажется разумным, что в данном случае обратная совместимость превзошла чувствительность современного языкового дизайна.


Это обсуждалось здесь несколько раз, в последнее время в назначение Fortran на объявление и сохранение атрибута gotcha

вам не нужно открывать это поведение путем экспериментов, это четко указано в лучших учебниках.

разные языки различны и имеют разное поведение.

есть историческая причина такого поведения. Многие компиляторы для Fortran 77 и более ранних версий сохранили значения всех локальных переменные между вызовами процедур. Программисты не должны полагаться на такое поведение, но многие делали. Согласно стандарту, если вы хотите, чтобы локальная переменная (не общая) сохранила свое значение, вам нужно использовать "сохранить". Но многие программисты игнорировали это. В ту эпоху программы реже портировались на разные платформы и компиляторы, поэтому неправильные предположения могли никогда не быть замечены. Обычно эту проблему можно найти в устаревших программах -- текущие компиляторы Fortran обычно укажите переключатель компилятора для сохранения всех переменных. Было бы глупо, если бы языковой стандарт требовал, чтобы все локальные переменные сохраняли свои значения. Но промежуточным требованием, которое спасло бы многие программы, которые были небрежны с "сохранить", было бы требование, чтобы все переменные, инициализированные в их объявлениях, автоматически имели атрибут SAVE. Отсюда и то, что вы обнаружили....