Можно ли указать указатель производного типа данных на Фортране на внутренний тип данных? - PullRequest
0 голосов
/ 24 января 2019

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

Пример псевдокода

subroutine process_array(a)
  integer,target,intent(in) :: a(*)
  ! defined elsewhere
  ! type struct
  !   integer :: b
  !   integer :: c
  !   integer :: d
  ! end type struct
  type(struct), pointer :: temp_struct(:)

  temp_struct=>a(1:size(a))
  ! do something

end subroutine process_array

Этот массив "a" передается из различных подпрограмм и имеет огромный размер. Как только я получил массив вместо того, чтобы передавать массив дальше вниз вместе со структурой данных (в комментариях), мне стало интересно, смогу ли я «привести» его к производному типу и передать как таковой. Массив имеет результаты численного моделирования, которые подаются в мои модули, где я их нарезаю, нарезаю и работаю над ними. Преобразование их в производные типы очень помогло бы моему коду вместо того, чтобы справляться со смещениями и вести подсчет различных счетчиков. Я хочу избежать копирования, поэтому искал указатели.

1 Ответ

0 голосов
/ 24 января 2019

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

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

module testmod
    implicit none

    type view_t
        integer, pointer :: nx, ny, vec(:)
    endtype
contains

function makeview( arr ) result( v )
    integer, target, intent(in) :: arr( : )
    type(view_t) :: v

    v % nx  => arr( 1 )
    v % ny  => arr( 2 )
    v % vec => arr( 3 : 4 )
endfunction

endmodule

program main
    use testmod
    implicit none
    integer arr( 4 * 2 ), i, offset
    type(view_t) :: v, views( 2 )

! We suppose that arr(:) consists of 2 blocks of data (each have 4 integers).

    arr(:) = [( i, i = 1, size(arr) )]  !! dummy data
    print *, "arr = ", arr

! Create a view for the first block of arr(:).

    v = makeview( arr( 1 : 4 ) )
    print *, "v % {nx, ny} = ", v % nx, v % ny
    print *, "v % vec      = ", v % vec

! Create a set of views for all the blocks of arr(:).

    do i = 1, 2
        offset = (i - 1) * 4
        views( i ) = makeview( arr( offset + 1 : offset + 4 ) )
    enddo

    arr( 7:8 ) = arr( 7:8 ) * 100   !! modify the original array

    print *, "views( 1 ) % vec = ", views( 1 ) % vec
    print *, "views( 2 ) % vec = ", views( 2 ) % vec
end

Результат (тест gfortran-8.f90)

 arr =      1     2     3     4     5     6     7     8
 v % {nx, ny} =      1       2
 v % vec      =      3       4
 views( 1 ) % vec =      3       4
 views( 2 ) % vec =    700     800

Дополнительные примечания:

  • Мы также можем использовать associate, чтобы опустить объявление переменной представления (foo), но в этом случае кажется, что мы не можем изменить foo % vec и т. Д. (Возможно, потому что это выражение).
    associate( foo => makeview( arr( 1:4 ) ) )
      print *, foo % vec  !! OK
      ! foo % vec = 100   !! error
    endassociate
  • Другим подходом может быть использование производного типа с компонентами без указателя и использование c_f_pointer(). Этот подход, кажется, работает, если все компоненты имеют примитивные типы по умолчанию (скажем, все целые числа по умолчанию), но в противном случае могут возникнуть проблемы (скажем, сочетание целочисленной и двойной точности) из-за заполнения (не очень уверен ...). Поэтому я думаю, что этот подход может быть полезен, но требует гораздо большей осторожности («небезопасно»).
    type altview_t
        sequence   !(not necessary for uniform integers?)
        integer :: nx, ny, vec(2)
    endtype
    type(altview_t), pointer :: altview( : )
    call c_f_pointer( c_loc( arr(1) ), altview, [ size(arr) / (sizeof(altview)/4) ] )
    print *, altview( k ) % vec
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...