ФОРТРАН ОБЩИЙ блок инициализации
Новичок на Фортране, меня попросили поработать над старой базой кодов на Фортране, написанной на Фортране 77 с помощью компилятора Salford/Silverfrost (первоначальный разработчик умер).
Оригинальный разработчик использует по имени COMMON
широко блокирует (для эмуляции глобальных переменных, AFAIU), и он использует EQUIVALENCE
(повторно) инициализировать блоки, когда это необходимо, как в следующем фрагменте кода:
IMPLICIT REAL*8 (A-H,O-Z)
COMMON/COMMF2D/
* ASCN(0:99,0:20,0:4)
*,FEMPTY2(8700)
DIMENSION KLCKF2D(38400)
EQUIVALENCE (KLCKF2D,ASCN)
DO I= 1,38400
KLCKF2D(I)= 0
END DO
Это приемлемая практика программирования или просто взлом? Кроме того, поскольку я пытаюсь перенести код на GFortran, он переносимый? (Я понимаю, что объявления вроде REAL*8
это просто подсказки компилятору и не гарантировано)
2 ответа
EQUIVALENCE
ничего не делает, конечно ничего не инициирует, EQUIVALENCE
это определение или декларация. В эти дни (и с момента публикации стандарта Fortran 90 с постоянно растущей силой) EQUIVALENCE
это взлом, и его следует избегать везде, где это возможно.
Оператор объявляет, что 2 переменные совместно используют хранилище (то, что стандарты Fortran называют ассоциацией хранилища). Одно из объяснений этого состоит в том, что имена, которые эквивалентны, являются просто псевдонимами, но (ab-) использование этого выражения позволяет программисту делать некоторые другие вещи, которые, как считают профессиональные инженеры 21-го века, считаются хитрыми.
Например, и это относится к фрагменту, который вы опубликовали, EQUIVALENCE
может использоваться, чтобы переменные разных типов совместно использовали одно и то же хранилище. У вас есть массив с именем ASCN
который (неявно) типа REAL*8
эквивалентно массиву под названием KLCKF2D
который (опять же неявно) типа INTEGER
, Это означает, что если вы ссылаетесь на хранилище под одним именем, битовые шаблоны интерпретируются как REAL
с, используя другое имя, они INTEGER
s - и обратите внимание, что битовый шаблон для реального со значением 100.0
не будет (конечно) интерпретироваться как целое число 100
,
И хакерство не останавливается там. Один эффект от COMMON
Объявление блока должно положить переменные в память, в вашем случае 10500 (= 100*21*5)
элементы ASCN
сопровождаются 8700
элементы FEMPTY2
, С небольшим умножением и сложением вы обнаружите, что 38400 = 2*(10500+8700)
что соответствует целочисленному размеру по умолчанию в этой программе, равному 4 байтам, т.е. половине размера REAL*8
Используется в других переменных. Итак, массив KLCKF2D
больше чем ASCN
но оригинальный программист знал, что следующий 17400
байты будут заняты FEMPTY2
,
Так что да, это может быть способ установки всех битов в этой части данных в памяти вашей программы в 0
, но это (сейчас считается) ужасный хак. Но он должен быть переносимым - последующие стандарты Фортрана были очень консервативны в отношении удаления устаревших функций из языка и разработчиков компиляторов, тем более что обратная совместимость ОЧЕНЬ важна для программистов на Фортране.
Да, и чтобы ответить на ваш вопрос, да COMMON
блоки были (обратите внимание на прошедшее время) способом FORTRAN77 объявления и использования глобальных переменных. В наши дни язык предлагает гораздо более безопасный вариант объявления переменных для общего доступа, оборачивая их в MODULE
а также USE
связывая их.
Я бы не удивился, увидев такую строчку
COMMON/COMMF2D/KLCKF2D(38400)
в вашем коде, COMMON
блоки также могут быть (ab-) использованы для переименования и перепечатывания мест хранения.
Несмотря на то, что я давлю ваш старый код, в наши дни также не одобряют неявную типизацию, гораздо лучше явно печатать все объявления.
Ну, портативная или нет, практика была ... обычным явлением. (Земляной юмор. Орк. Орк.) Я приведу вам пример: данные в исходном коде игры Zork, которую я обновил, - это практически не что иное, как обычные блоки и эквиваленты. https://github.com/LydiaMarieWilliamson/zork-fortran
В соседних переводах C вы увидите, как это разыгрывается в C. Переводчик f2c испытывает трудности с обработкой эквивалентностей и общих блоков (как вы увидите в моем журнале переводов). Мой совет состоит в том, чтобы перекодировать все это на C или C++ и исправить там. Это сделает его более доступным для большего числа программистов. Я готовлюсь сделать это со всем дистрибутивом LAPACK (как вы, возможно, уже заметили) - это от 500000 до 1000000 строк.
Эквивалент C самой структуре также является лучшим способом создания многомерных массивов. Вы выделяете только один базовый сегмент для всего объекта. Затем для второго измерения вы выделяете в него сегмент указателей - растр. Затем для третьего измерения вы выделяете сегмент указателей на это ... и так далее.
Не существует хорошей эквивалентности языка C для самого утверждения эквивалентности. (Земляной юмор. Орк. Орк.) Вместо этого эквивалент эквивалентности лучше всего найти в C++ с использованием ссылочных типов. В C++ вы также можете более напрямую отображать индексы Fortran, поскольку сами индексы (с скобками типа [] и ()) являются программируемым оператором. Таким образом, вы можете напрямую перевести эквивалентную структуру и ее методы индексации как есть - как статическую структуру без необходимости в вышеупомянутом распределении.