【问题标题】:gfortran no-traditional preprocessorgfortran 非传统预处理器
【发布时间】:2018-06-08 17:16:40
【问题描述】:

我想编写一个重载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

在浏览了这个论坛和谷歌之后,我推断问题是这样的:

预处理器以传统模式运行。

事实上,cpp --traditional 表现出与gfortran -E -cpp 相同的行为

所以这是我的问题:

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

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

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

【问题讨论】:

  • 对 (2) 的回答是“否”。 (3)的答案是直接使用 cpp 如您所演示的。使用 (3) 为可能的奇怪结果做好准备,因为现代 C 预处理器语法和 Fortran 语法存在冲突。 (1) 的答案可能在于 Fortran 的子模块功能。
  • cpp 在非传统模式下会将// 视为注释分隔符。 gfortran 使用传统模式,因为必须不破坏 Fortran 代码。

标签: fortran gfortran preprocessor


【解决方案1】:
  1. 您可以使用依赖于编译器的预处理器宏来实现您正在寻找的东西。请注意,Concatenating an expanded macro and a word using the Fortran preprocessor 已经讨论并回答了类似的案例。我相信它可以适应您的情况如下:

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

    注意

    • The above-mentioned answer 声明“基本上大多数 Fortran 编译器(即 Intel 和 PGI)使用带有标记粘贴操作符的相对普通的 C 预处理器”。我的理解是 NAG 编译器也无法处理##,因此需要添加到异常中。
    • 在上面的最后一个#define 中,swap,TYPE_KIND 之间没有空格。
  2. 据我所知没有。
  3. 正如@Vladimir 在 cmets 中指出的那样,您可能不想这样做,因为它会破坏 Fortran 连接运算符 //

【讨论】:

  • 其他编译器经常使用 fpp,这是一种从 C 预处理器(可能不是 GNU 预处理器)派生的独立预处理器,并略微适用于 Fortran。
  • #ifdef __GFORTRAN__ #define CONCAT(x,y) x/**/y 也可以在更简单的情况下工作。 stackoverflow.com/questions/39679689/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多