2013-03-27 2 views
9

Каковы практические различия между использованием модулей с оператором use или отдельными файлами с оператором include? Я имею в виду, если у меня есть подпрограмма, которая используется во всей программе: когда или почему я должен помещать ее внутри модуля или просто писать в отдельном файле и включать ее в каждую другую часть программы, где она должна быть используемый?Разница между INCLUDE и модулями в Fortran

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

ответ

16

Концептуальные различия между двумя картами до очень значительных практических различий.

Линия INCLUDE работает на уровне источника - она ​​выполняет простое («немое») включение текста. В отсутствие какой-либо специальной интерпретации процессора «имя файла» (нет требования для этого фактически быть файлом) в строке включения полный источник может быть легко скомбинирован вручную программистом и передан компилятору без разницы, что -со-всегда в семантике источника. Включенный источник не имеет реальной интерпретации в изоляции - его смысл полностью зависит от контекста, в котором появляется строка включения, которая ссылается на включенный источник.

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

Обычно то, что кто-то использует линию включает в надежда делать то, что модули были фактически разработаны сделать.

Пример проблемы:

  • Поскольку декларации сущностей могут быть распределены по нескольким ведомостям объекты, описываемые включенным источником не может быть то, что вы ожидаете. Рассмотрим следующий источник должны быть включены:

    INTEGER :: i

    В изоляции это выглядит следующим образом объявляет имя i как целое скаляр (или, возможно, в зависимости кто знает?!). Теперь рассмотрим следующую сферу, которая включает в себя выше:

    INCLUDE "source from above"
    DIMENSION :: i(10,10)

    i теперь ранга два массива! Возможно, вы хотите сделать это POINTER? ПОЛЕЗНОЕ? Фиктивный аргумент? Возможно, это приводит к ошибке, или, возможно, это действительно источник! Бросьте неявное типирование в микс, чтобы действительно создать потенциальную забаву.

    Объект, определенный в модуле, «полностью» определяется модулем. Атрибуты, специфичные для области использования, могут быть изменены (VOLATILE, доступность и т. Д.), Но основной объект остается неизменным. Вызовы имени вызываются явно, и их можно легко обойти с предложением переименования в заявлении USE.

  • У Fortran есть ограничения на упорядочение операторов (спецификации должны доставляться перед исполняемыми инструкциями и т. Д.). Включенный источник также подвергается этим ограничениям, опять же в контексте точки включения, а не точки определения источника.

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

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

  • Нужно ли иметь какое-либо глобальное состояние для совместного использования связанных процедур и вы хотите использовать include? Позвольте мне представить вам общие блоки и связанную с ними базовую концепцию объединения последовательностей ...

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

    Переменные модуля делают общие блоки и связанные с ними зла совершенно ненужными.

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

    Как уже упоминалось, компиляторы автоматически получают информацию о интерфейсе модульной процедуры (знание компилятора является «явным», потому что на самом деле он видел код процедуры - отсюда и термин «явный интерфейс»). Нет необходимости программисту делать что-то еще.

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

Другие плакаты упоминали исходный код организации преимущества модулей - в том числе способность к группирования связанных процедур и других «вещей» в одном пакете, с контролем над доступностью внутренних деталей реализации.

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

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

+0

Итак, нет никакого недостатка в разделении подпрограмм в разных файлах, а затем использование include внутри модуля, правильно? Раньше я никогда не слышал о подмодулях. – Nordico

+1

Я бы рассматривал это только в том случае, если у меня были очень большие исходные файлы или как часть миграции исходного кода. Если возможно, я бы сначала подумал о том, чтобы разбить модуль на несколько «дочерних» модулей, которые затем агрегируются вместе с операторами USE в родительском модуле. Однако при сложных зависимостях типа/процедуры и/или в том, как работает доступность Fortran PUBLIC/PRIVATE, использование дочерних модулей может быть не всегда возможным. Вы можете обнаружить, что сшивание источника для модуля вместе с INCLUDE приводит к путанице с некоторыми системами сборки. – IanH

6

Размещение процедур в модулях и использование этих модулей делает интерфейс процедуры явным. Он позволяет компилятору Fortran проверять соответствие между фактическими аргументами в вызове и фиктивными аргументами процедуры. Это защищает от множества ошибок программиста. Явный интерфейс также необходим для некоторых «продвинутых» функций Fortran> = 90; например, необязательные или ключевые аргументы. Без явного интерфейса компилятор не будет генерировать правильный вызов. Простое включение файла не дает этих преимуществ.

+1

Я бы пошел дальше, я не думаю, что есть какие-то веские причины использовать файлы include. –

+0

@HighPerformanceMark: Общее программирование бедных людей? – eriktous

+1

Как я писал * Я не знаю никаких веских причин использовать файлы include *. Но это мнение –

3

Ответ М.С.Б. большой, и, вероятно, это самая важная причина, по которой предпочтительнее использовать модули. Я хотел бы добавить еще несколько мыслей.

Использование модулей уменьшает ваш скомпилированный двоичный размер, если это то, что важно для вас. Модуль компилируется один раз, и когда вы используете use, вы символически загружаете этот модуль для использования кода. Когда вы делаете include файл, вы фактически вставляете новый код в свою рутину. Если вы используете include, это может привести к увеличению вашего бинарного файла и увеличению времени компиляции.

Вы также можете использовать модули для подделки кодировки стиля ООП в Fortran 90 посредством умного использования публичных и частных функций и пользовательских типов в модуле. Даже если вы не хотели этого делать, он обеспечивает хороший способ группировки функций, которые логически принадлежат друг другу.

Смежные вопросы