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

После долгой мучительной отладки я считаю, что нашел уникальное свойство Фортрана, которое я хотел бы проверить здесь, в 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.

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

Я, конечно, мог бы исправить эту проблему, просто добавив строку negative = .FALSE. после объявления переменной в моей функции и подпрограмме.

Однако мне кажется очень странным, что это необходимо.

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

9
задан EMiller 18 August 2010 в 05:30
поделиться

3 ответа

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

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

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

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

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

13
ответ дан 4 December 2019 в 10:30
поделиться

Здесь это обсуждалось несколько раз, в последний раз на Назначение Fortran для объявления и атрибут SAVE gotcha

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

Разные языки разные и ведут себя по-разному.

У такого поведения есть историческая причина. Многие компиляторы для Fortran 77 и ранее сохраняли значения ВСЕХ локальных переменных при вызовах процедур. Программисты не должны были полагаться на такое поведение, но многие полагались. Согласно стандарту, если вы хотите, чтобы локальная переменная (не ОБЩАЯ) сохраняла свое значение, вам нужно было использовать «СОХРАНИТЬ». Но многие программисты проигнорировали это. В то время программы реже переносились на другие платформы и компиляторы, поэтому неверные предположения могли никогда не быть замечены. Эта проблема часто встречается в устаревших программах - современные компиляторы Fortran обычно предоставляют переключатель компилятора для сохранения всех переменных. Было бы глупо со стороны стандарта языка требовать, чтобы все локальные переменные сохраняли свои значения. Но промежуточным требованием, которое могло бы спасти многие программы, которые небрежно использовали «SAVE», было бы требование, чтобы все переменные, инициализированные в их объявлениях, автоматически имели атрибут SAVE. Отсюда то, что вы обнаружили ....

3
ответ дан 4 December 2019 в 10:30
поделиться

Это не слишком отличается от статических переменных в области видимости функции в C или C++.

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

Изначально FORTRAN даже не поддерживал рекурсию, не было динамической памяти распределения, программы играли во всевозможные каламбурные игры с ОБЩИМИ блоками. и ЭКВИВАЛЕНТНОСТЬ процедуры могут иметь несколько точек входа.... поэтому модель памяти была в основном для компилятора/компоновщика, чтобы выложить все, даже локальные переменные и числовые литеральные константы в фиксированные места хранения, а не на стек. Если бы вы хотели, вы могли бы даже написать код, который изменил бы значение "2" на "42"!

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

4
ответ дан 4 December 2019 в 10:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: