gfortran нетрадиционный препроцессор - PullRequest
0 голосов
/ 08 июня 2018

Я хочу написать модуль, перегружающий подпрограмму swap, которая принимает массив и два индекса и меняет местами два элемента.

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

module mod_swap

    use iso_fortran_env
    implicit none

    interface swap
        module procedure swap_int64, swap_int32, swap_int16, &
            swap_real64, swap_real32
    end interface swap

    public :: swap
    private :: swap_int64, swap_int32, swap_int16, &
        swap_real64, swap_real32

contains

#define VAR_TYPE real
#define TYPE_KIND real64
#include  "swap.inc"
#undef TYPE_KIND

#define TYPE_KIND real32
#include  "swap.inc"
#undef TYPE_KIND
#undef VAR_TYPE

#define VAR_TYPE integer
#define TYPE_KIND int64
#include  "swap.inc"
#undef TYPE_KIND

#define TYPE_KIND int32
#include  "swap.inc"
#undef TYPE_KIND

#define TYPE_KIND int16
#include  "swap.inc"
#undef TYPE_KIND
#undef VAR_TYPE

end module mod_swap

с swap.inc, являющимся:

#define PASTER(x,y) x ## _ ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define SWAP EVALUATOR(swap, TYPE_KIND)

    subroutine SWAP(a, i, j)
        implicit none
        VAR_TYPE(kind=TYPE_KIND), intent(inout) :: a(:)
        integer, intent(in) :: i, j
        VAR_TYPE(kind=TYPE_KIND) t
        t = a(i)
        a(i) = a(j)
        a(j) = t
    end subroutine SWAP

Когда я запускаю gfortran -o test.o -c -cpp test.F90, он выходит из строя, а когда я запускаю gfortran -E -cpp test.F90, я выясняю почему:Макрос SWAP был расширен до swap ## _ ## int16, а не swap_int16, как ожидалось.

Однако cpp напрямую работает:

$ cpp test.F90 > test.f90
$ gfortran -c -o test.o test.f90

После просмотра этого форума и Google в целомЯ пришел к выводу, что проблема заключается в следующем:

Препроцессор работает в традиционном режиме.

И действительно, cpp --traditional демонстрирует то же поведение, что и gfortran -E -cpp

Итак, вот мои вопросы:

  1. Есть ли лучший способ реализовать эту процедуру, чтобы мне не пришлось повторять одни и те же инструкции только потому, что тип массиваизменился(Обратите внимание, что переменная t должна иметь тот же тип, что и a).

  2. Есть ли способ заставить gfortran использовать нетрадиционный препроцессор?

  3. Если нет, то как мне поступить так, как я хочу, с традиционным препроцессором?

1 Ответ

0 голосов
/ 08 июня 2018
  1. Вы можете реализовать то, что ищете, используя макросы препроцессора, зависящие от компилятора.Обратите внимание, что подобный случай уже обсуждался и получен ответ в Конкатенация расширенного макроса и слова с использованием препроцессора Fortran .Я полагаю, что это может быть адаптировано к вашему случаю следующим образом:

    #if defined(__GFORTRAN__) || defined(NAGFOR)
    #define PASTE(a) a
    #define ADD_TRAIL_USCORE(a) PASTE(a)_
    #define CAT(a,b) ADD_TRAIL_USCORE(a)b
    #else
    #define PASTE(a,b) a ## _ ## b
    #define CAT(a,b) PASTE(a,b)
    #endif
    
    #define SWAP CAT(swap,TYPE_KIND)
    

    Обратите внимание, что

    • Вышеупомянутый ответ утверждает, что "в основномбольшинство компиляторов Фортрана (то есть Intel и PGI) используют относительно обычный C-препроцессор с оператором вставки токена ".Насколько я понимаю, компилятор NAG также не может работать с ##, и, следовательно, его необходимо добавить к исключению.
    • В последнем #define выше нет пробела между swap, иTYPE_KIND.
  2. Не знаю, о чем я знаю.
  3. Как отметил @Vladimir в комментариях, вы, вероятно, не хотите этого делать, поскольку это нарушит сцепление Фортрана.оператор //.
...