Фортран указатель на целевой массив параметров - PullRequest
2 голосов
/ 05 июня 2019

У меня есть несколько массивов параметров с разными именами в модуле:

real*8, parameter :: para1(*) = [43.234, 34.0498, ...
real*8, parameter :: para2...

В процедуре в этом модуле

subroutine sub(n,...
...
end

Я хочу использовать para1, когда n=1, para2, когда n=2 и т. Д. Есть несколько решений, одно из которых состоит в создании массива paras = [para1, para2 ...] и индекса правильно, который работает нормально. Но я хочу попробовать использовать указатель

real*8, pointer :: ptr(:) 

и назначьте его различным массивам параметров в зависимости от n, но проблема в том, что "PARAMETER attribute conflicts with TARGET attribute at (1)". Если я удалю атрибут parameter, подпрограмма станет менее безопасной и предполагается, что атрибут SAVE.

Я что-то упустил или почему мы не можем объединить parameter и target? И есть ли способ обойти это для этой цели?

Ответы [ 2 ]

2 голосов
/ 05 июня 2019

Атрибуты parameter и target действительно конфликтуют. Объект с атрибутом target должен быть переменной (Fortran 2018 8.5.17, C861); именованная константа (объект с атрибутом parameter) не является переменной (F2018, 8.5.13, C850).

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

Вне чистой процедуры и фиктивного аргумента intent(in) самый заманчивый запрет - с переменной защищенного модуля:

module pars
  real, save, target, protected :: para1(74) = [...]
  real, save, target, protected :: para2(1) = [6]
end module

subroutine sub (...)
  use pars
  real, pointer :: p
  p => para1
end subroutine sub

Защищены ли значения от изменения вне модуля pars? Увы, даже если бы это было правдой, это не полезно: будучи защищенным, мы не можем даже указать указатель на переменные модуля.

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

0 голосов
/ 06 июня 2019

Следуя предложению @ ja72 в комментарии, это попытка использовать один 2D-массив для параметров. Это прекрасно работает с gfortran-8.2 (на MacOS10.11).

program main
    implicit none
    integer i
    integer, parameter :: para1(*) = [1, 2, 3, 4, 5]
    integer, parameter :: para2(*) = [6, 7]
    integer, parameter :: N1 = size(para1), N2 = size(para2), N = max(N1, N2)
    integer, parameter :: params(N, 2) = &
            reshape( [ para1, (0, i = 1, N - N1), &
                       para2, (0, i = 1, N - N2) ], [N, 2] )

    print *, "para1 = ", params( :, 1 )
    print *, "para2 = ", params( :, 2 )

    print *, "Input i"
    read *, i
    print *, params( :, i )
end

$ gfortran-8 test.f90 && ./a.out

 para1 =            1           2           3           4           5
 para2 =            6           7           0           0           0
 Input i
1
           1           2           3           4           5

Однако, поскольку код становится немного сложнее (из-за изменения формы) и может не работать со старыми компиляторами, может быть проще использовать массивы без параметров ...

...