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

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

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

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

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

Ответы [ 3 ]

13 голосов
/ 18 августа 2010

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

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

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

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

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

4 голосов
/ 18 августа 2010

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

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

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

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

3 голосов
/ 18 августа 2010

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

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

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

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

...