Указатель на производный тип, который содержит размещаемый массив

Вообще говоря, я хочу переименовать размещаемые переменные в производном типе, которые передаются через аргументы подпрограммы. Написание всего с "производным%type_xx" не так приятно. Кроме того, я не хочу тратить дополнительную память на копирование значений производного типа в новую переменную, которая стоит новой выделенной памяти. Кроме того, я знаю, что по многим причинам распределенные массивы предпочтительнее, чем указатели. Я пытаюсь определить указатели на размещаемую переменную, но не удалось. Я попробовал это, потому что я хочу упростить мой код, чтобы он был читабельным и не был слишком длинным. Интересно, есть ли способ достижения цели? Благодарю.

Вот демонстрационный код:

Module module_type
IMPLICIT NONE
    TYPE type_1
        REAL,ALLOCATABLE                  ::      longname_1(:), longname_2(:)
    END TYPE
END MODULE

!------------------------------------------------------------------------------------------
SUBROUTINE TEST(input)
    USE MODULE module_type
IMPLICIT NONE
    TYPE(type_1)                          ::      input
    input%longname_1 = input%longname_1 + input%longname_2   ! Use one line to show what I mean
END SUBROUTINE

И вот что не удалось:

Module module_type
IMPLICIT NONE
    TYPE type_1
        REAL,ALLOCATABLE                  ::      longname_1(:), longname_2(:)
    END TYPE
END MODULE

!------------------------------------------------------------------------------------------
SUBROUTINE TEST(input)
    USE MODULE module_type
IMPLICIT NONE
    TYPE(type_1),TARGET                    ::      input

    REAL,POINTER                           ::      a => input%longname_1 &
                                                 & b => input%longname_2

    a = a + b   ! much better for reading
END SUBROUTINE

Это кажется небольшой проблемой, но я хотел бы прочитать мой код без особых проблем в будущем. Так какой же самый лучший вариант? Большое спасибо.

2 ответа

Решение

Вы можете использовать конструкцию ASSOCIATE, чтобы связать простое имя с более сложным указателем или выражением.

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

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

Использование указателей для такого простого именования имен может снизить способность компилятора оптимизировать код. Что-то вроде ASSOCIATE должно быть предпочтительным.

Обновление: после того, как @IanH сделал свой комментарий, я вернулся, чтобы проверить: я был совершенно и совершенно не прав, почему ваш код провалился. Как он указал в своем ответе, основная проблема заключается в том, что указатель и цель должны иметь одинаковый ранг, поэтому вам придется объявить a а также b как:

real, pointer :: a(:), b(:)

Во-вторых, прежде чем вы сможете на самом деле указывать эти указатели на цели, цели должны быть распределены. Вот пример, который работает:

program allocatable_target

    implicit none
    type :: my_type
        integer, allocatable :: my_array(:)
    end type my_type
    type(my_type), target :: dummy
    integer, pointer :: a(:)

    allocate(dummy%my_array(10))
    a => dummy%my_array
    a = 10
    print *, dummy%my_array

end program allocatable_target

Если у вас есть совместимый с Fortran 2003 компилятор, вы можете использовать associate - который специально предназначен для такого рода вопросов. Вот пример:

program associate_example

    implicit none
    type :: my_type
        integer, allocatable :: long_name_1(:), long_name_2(:)
    end type my_type

    type(my_type) :: input

    integer :: i
    allocate(input%long_name_1(100), input%long_name_2(100))

    associate (a=>input%long_name_1, b=>input%long_name_2)
        a = (/ (i, i = 1, 100, 1) /)
        b = (/ (2*i+4, i = 1, 100, 1) /)
        a = a + b
    end associate

    print *, input%long_name_1

end program associate_example

Внутри associate блок, вы можете использовать a а также b как сокращение для объявленных переменных с более длинными именами.

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

Другие вопросы по тегам