Создавать объекты-обертки для де-свертывания ужасного кода на Фортране?
Я должен поработать над неким устаревшим Fortran, хотя я могу использовать самые последние компиляторы.
Код хранит огромное количество данных в одномерных массивах.
Например,
PROGRAM horrible_coding
IMPLICIT EVERYTHING ! Sarcasm
REAL, DIMENSION(1000) :: data
INTEGER, DIMENSION(50) :: info_location
! Somewhere, info is read in and stored temporarily as info_1, info_2, etc.
data(1:3) = info_1
data(4:9) = info_2
...
data(134:192) = info_n
Связь между элементами в DATA
массив идти с какими частями info
хранится во втором массиве. Что-то вроде:
info_location(1) = 1
info_location(2) = 4
info_location(n) = 134
Вот так. Значение каждого элемента info_location
Массив относится к первому элементу массива данных, где вы можете найти соответствующую информацию.
Так, например, если вы хотите получить данные для info_7, вам нужно сделать следующее:
size_of_info_7 = info_location(8) - info_location(7)
ALLOCATE(data_for_info_7(size_of_info_7))
data_for_info_7 = data(info_location(7) : info_location(7) + size_of_info_7 - 1)
К настоящему времени вид этого безумия, возможно, заставил кровь начать стрелять из твоих глаз, поэтому я прошу прощения.
Я хотел бы создать экземпляры объекта и сохранить все соответствующие данные для каждой части информации в качестве данных экземпляра. И пока я переношу вещи в 2003, я бы создал методы экземпляров для получения и установки данных экземпляров.
Я не хочу переписывать код, но хочу поставить эту модернизацию поверх того, что уже есть.
Я полагаю, что я могу сделать это, сделав данные экземпляра объекта просто указателями, которые указывают на фактические элементы data
массив, который содержит соответствующую информацию.
Это разумная вещь?
Могу ли я создать в Фортране объекты, данные экземпляров которых преимущественно являются указателями?
Я не решаюсь начать эту задачу, не разбрасывая идею стекпотока.
2 ответа
Могу ли я создать в Фортране объекты, данные экземпляров которых преимущественно являются указателями?
Я не уверен, что вы имеете в виду, но вы определенно можете сделать что-то вроде:
type data_ptr
real,dimension(:),pointer :: data
end type
И вы также можете сделать массивы этих типов:
type(data_ptr),dimension(:),allocatable :: some_name
(может быть указательным или статическим, как вы хотите.)
Затем, если исходные данные TARGET
атрибут, вы можете использовать:
some_name(i)%data => data(lower:upper)
Вы также можете переназначить указатель на разные нижние границы, процесс выше дает ему нижнюю границу 1.
Я нахожу код, который вы опубликовали, немного запутанным. Я ожидаю, что вы знаете, что линии
data(1:3) :: info_1
data(4:9) :: info_2
...
data(134:192) :: info_n
не являются синтаксически действительными Fortran (любого поколения). Я думаю, что я могу истолковать то, что вы пытаетесь сказать нам, но не хотел бы давать советы, основанные на (неправильной) интерпретации. Кроме того, вы бросаете объекты, такие как info_1, info_2
в смесь без уточнения их определения и декларации. Я не уверен, действительно ли info_1
это то же самое, что info_location(1)
,
Если я понимаю, что вы опубликовали, у вас есть довольно распространенная (в старом коде Фортрана) конструкция, в которой массив данных фиксированного размера (условно называемый data
здесь), который используется для хранения коллекции предметов. Затем у вас есть индексный массив (называется info_location
) который содержит индексы в данные в начале каждого элемента. Очень странно, что этот индексный массив имеет тип REAL, я ожидаю, что он будет INTEGER, чтобы вы могли писать такие выражения, как:
data(info(3):info(4)-1))
Это, конечно, не заставляет мои глазные яблоки кровоточить, возможно, я слишком долго программировал на Фортране, но это выглядит совершенно разумным для меня! Один вариант, который вы должны рассмотреть, это разыграть info_location
интегрировать как-то и использовать это как индексный массив. Или, вы можете делать такие приведения, как и когда это необходимо, написав такие строки:
data(int(info(3)):int(info(4))-1))
Лично я бы сделал массив индексов INTEGER, REAL - неправильный тип для индексов массива.
Затем вы пишете
Так, например, если вы хотите получить данные для info_7, вам нужно сделать следующее:
size_of_info_7 = info_location(8) - info_location(7)
ALLOCATE(data_for_info_7(size_of_info_7))
data_for_info_7 = data(info_location(7) : info_location(7) + size_of_info_7 - 1)
Поскольку вы не уточнили, что именно info_7
или же data_for_info_7
Я немного смущен этим. Если вы используете неявную типизацию, то size_of_info_7 будет REAL, и ваш оператор ALLOCATE завершится неудачно, требуя INTEGER для размера выделенного объекта.
Я предполагаю, что data_for_info_7
это, вероятно, размещаемый массив REAL. Если info_location
были типа INTEGER вы могли бы просто написать:
ALLOCATE(data_for_info_7, source = data(info_location(7) : info_location(8) - 1))
Владимир Ф уже дал совет по использованию указателей для очистки вашего кода. Другой подход заключается в использовании конструкции ASSOCIATE. Вы можете написать в соответствующих точках вашего кода что-то вроде:
ASSOCIATE(data_for_info_7 => data(info_location(7) : info_location(8) - 1))
сопоставляя это с END ASSOCIATE
заявление в нужном месте. Это эффективно определяет псевдоним для секции массива в конструкции ASSOCIATE.
Итак, округлим:
- Тип
info_location
массив неверен. - Оставляя это в стороне от оригинального проекта с массивом данных и другим массивом индексов, (безусловно, было) вполне разумно.
- У вас есть несколько вариантов обновления кода, включая указатели и ассоциации.