gfortran 非传统预处理器

gfortran no-traditional preprocessor

我想编写一个重载 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之后,我推断出问题是这样的:

The preprocessor is run in traditional mode.

事实上,cpp --traditional 表现出与 gfortran -E -cpp

相同的行为

所以这是我的问题:

  1. 有没有更好的方法来实现这个例程,这样我就不必因为数组类型发生了变化而重复相同的指令。 (请注意,变量 t 需要与 a 具有相同的类型)。

  2. 有没有办法让gfortran使用非传统的预处理器?

  3. 如果没有,我将如何用传统的预处理器做我想做的事情?

  1. 您可以使用依赖于编译器的预处理器宏来实现您正在寻找的内容。请注意,在 中已经讨论并回答了类似的案例。我相信它可以按如下方式适应您的情况:

    #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)
    

    注意

    • 表示 "basically most Fortran compilers (i.e. Intel and PGI) use a relatively normal C-preprocessor with a token pasting operator"。我的理解是 NAG 编译器也无法处理 ##,因此需要添加到异常中。
    • 上面最后的#defineswap,TYPE_KIND之间没有space。
  2. 据我所知没有。
  3. 正如@Vladimir 在评论中指出的那样,您可能不想这样做,因为它会破坏 Fortran 连接运算符 //.