Создание нескольких модулей из нескольких общих блоков fortran 77

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

Нужно ли включать операторы «использования» в программу, которая инициализирует переменные в модуле, или я должен включать программу в модуль? Обычно я бы использовал для этого общие блоки, но я пытаюсь реализовать модули, потому что я думаю, что они помогут моему коду оставаться читаемым по мере увеличения сложности.

ПРИМЕЧАНИЕ. Некоторые значения переменных в модулях должны иметь возможность изменяться при передаче из одной программы в другую.

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

Я использую gfortran 4.6.1

Main.f

program main
use Words
use Vals
double precision x,y,z
character*5 Greet
integer i

Greet = 'Hello'
x = 4.1
y = 5.2
z = 10.0
i = 3

call foo ()

end program main

subroutine foo ()
use Words
use Vals

print *, Greet

z = x + y
print *, z

print *, i

end subroutine

module Words
character*5 Greet
save
end module

module Vals
double precision x,y
integer int
save
end module

person kxk7607    schedule 10.01.2013    source источник


Ответы (3)


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

Обычно вы должны сначала скомпилировать модули, прежде чем они будут использоваться, чтобы компилятор «знал» о них, когда встречает оператор использования. Это делается либо путем помещения их первыми в файл, либо путем компиляции их файлов в первую очередь. Вот ваш пример переупорядочен:

module Words
character*5 Greet
save
end module

module Vals
double precision x,y
integer i
save
end module

module my_subs

contains

subroutine foo ()
use Words
use Vals
double precision :: z

print *, Greet

z = x + y
print *, z

print *, i

end subroutine

end module my_subs


program main
use Words
use Vals
use my_subs


Greet = 'Hello'
x = 4.1
y = 5.2

i = 3

call foo ()

end program main
person M. S. B.    schedule 10.01.2013
comment
Начиная с фортрана 2003 (или это был 2008 год?) все переменные модуля автоматически сохраняются. - person eriktous; 10.01.2013
comment
Это было очень полезно. Спасибо. Надеюсь, на выходных я смогу успешно внедрить модули в свою программу. - person kxk7607; 12.01.2013
comment
Использование модулей предпочтительнее использования include? В настоящее время у меня есть много операторов включения в конце файла MAIN. Насколько я понимаю, включенные подпрограммы неявно доступны друг другу. Это правильное понимание? Должен ли я вместо этого внедрять модули? У меня уже есть работающая программа, но если использование модулей облегчит людям работу по редактированию моей программы в будущем, я потрачу время на их реализацию. - person kxk7607; 18.01.2013
comment
Если вы размещаете свои подпрограммы после основной программы с оператором contains, я рекомендую вместо этого поместить их в модуль. Во-первых, подпрограммы после оператора contains в основной программе наследуют переменные основной программы, которые не маскируются их локальными переменными. Это может быть очень запутанным. Во-вторых, наличие подпрограмм в модуле позволяет повторно использовать их в других программах. Наконец, вы также можете группировать переменные модулей и подпрограммы в различные модули по логическим связям. - person M. S. B.; 18.01.2013
comment
Я использую операторы include, а не операторы contain (есть ли разница?). Конец моего MAIN выглядит так end program main include "./SUBROUTINES/Sub1.f" include "./SUBROUTINES/Sub2.f" Каждая подпрограмма находится в отдельном файле. Поможет ли использование модулей? Большинство подпрограмм написаны на стандарте ANSI fortran 77. Мне придется прочитать о синтаксисе и вложенности модулей, потому что я понял только около 1/2 того, что вы сказали! Вы дали мне хорошую отправную точку, хотя. - person kxk7607; 19.01.2013
comment
Размещение подпрограмм в модулях и последующее их использование очень полезно, поскольку позволяет компилятору проверять согласованность между фактическими аргументами и фиктивными аргументами, т. е. между аргументами в вызове и аргументами объявлений подпрограммы. Таким образом, компилятор улавливает множество ошибок программиста, и программирование выполняется быстрее. - person M. S. B.; 20.01.2013
comment
У меня есть функция func, подпрограмма subrout и главная main. Я хочу передавать значения между func и subrout, но мне не обязательно нужен main для доступа к этим значениям. Я планирую сделать модуль под названием subfunc и разместить func и subrout внутри этого модуля. Затем я помещаю use subfunc вверху файла main, где я также определяю модуль с именем vals. Я помещаю use vals сразу после объявлений подпрограмм и функций для subrout и func в модуле subfunc, но не включаю use vals в main. Дает ли этот пример правильное понимание модулей? - person kxk7607; 21.01.2013
comment
да. Альтернативой, позволяющей управлять доступом/видимостью элементов, но избегающей увеличения количества модулей, является ограничение элементов, к которым осуществляется доступ в операторе use с параметром only. - person M. S. B.; 22.01.2013

Есть несколько причин, по которым ваш код не будет компилироваться:

  1. Ваши модули располагаются после вашей основной программы, что означает, что они не будут скомпилированы к тому времени, когда вы use их туда добавите. Либо поместите их в отдельные файлы и скомпилируйте перед основной программой, либо поместите перед основной программой.

  2. Вы повторно объявляете переменные из своего модуля в основной программе, что компилятор интерпретирует как конфликт имен. Все переменные модуля с атрибутом public (который используется по умолчанию) станут доступны в той области, в которой вы use используете модуль; это называется "использовать ассоциацию". Другими словами, use vals достаточно, чтобы сделать доступными x, y и int.

Кроме того, модули больше похожи на одноэлементные объекты, чем просто на контейнеры данных. Они также могут содержать процедуры, перечисленные после оператора contains, что помогает группировать переменные и связанные процедуры вместе. Примером может быть объединение двух ваших модулей в один вместе с подпрограммой foo:

module vals
  implicit none

  double precision :: x = 4.1, y = 5.2
  integer :: i = 3
  character(5) :: greet = 'Hello'

contains
  subroutine foo()
    double precision :: z  ! New local variable

    print *, Greet

    z = x + y
    print *, z

    print *, i
  end subroutine
end module

Выше я использовал «новый» оператор с двойным двоеточием ::, который позволяет объявлять и инициализировать несколько переменных одновременно. Поскольку переменные модуля уже неявно save, это нормально.

В качестве альтернативы, если эти модули предназначены быть отдельными, вы также можете иметь contains разделов в своей основной программе (или любой подпрограмме) и поместить туда подпрограмму. Преимущество заключается в том, что процедуры, объявленные таким образом, всегда имеют явные интерфейсы, что значительно облегчает диагностику ошибок компилятором и даже требуется в некоторых новых случаях. Это одно из основных улучшений F90, поскольку F77 имел дело только с внешними подпрограммами и неявными интерфейсами.

person sigma    schedule 10.01.2013
comment
О черт, немного отошел и не увидел ответа MSB. Приносим извинения от Департамента по сокращению штатов. - person sigma; 10.01.2013

Самый простой способ сделать общие блоки — иметь один включаемый файл для каждого общего блока и сделать все свои объявления в включаемом файле. Таким образом, общий блок объявляется только в одном месте. Проблема необходимости конвертировать код для использования модулей просто волшебным образом исчезает.

Кроме того, если вы начинаете новый код, добавление префикса к имени переменной общего блока с тем же именем, что и у именованного общего блока, значительно упростит кодирование. Поначалу это боль, и примадонны, которые программировали годами, откажутся подчиняться. Люди, которые поддерживают код, найдут его очень простым: никаких greps или groks. Просто взглянув на название, вы узнаете, из какого общего блока оно происходит.

Сохранение того же соглашения с модулями также помогает. Если все имена подпрограмм и имена переменных начинаются с имени модуля, то, просто взглянув на имя, вы узнаете, из какого модуля оно взято.

person cup    schedule 17.03.2013
comment
Это очень плохой совет. Это особенно плохо в контексте вопроса и принятого ответа здесь, ОП уже переписывает модули. При правильном использовании они представляют собой гораздо лучший подход, чем обычные блоки и операторы включения. Преобразование кода для использования модулей — это не проблема, это возможность улучшить код. - person High Performance Mark; 17.03.2013