Сохраняет ли 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. Отсюда и то, что вы обнаружили....