【问题标题】:Unable to suppress bound checking无法抑制边界检查
【发布时间】:2016-09-16 15:13:18
【问题描述】:

首先,我不知道在使用 gfortran 时边界检查是自动的。使用以下代码:

gfortran -Wno-array-bounds initial_parameters.f08 derrived_types.f08 lin_alg.f08 constitutive_models.f08 input_subs.f08 Subprograms.f08 mainprog.f08 

我仍然收到编译时警告:

Warning: Array reference at (1) is out of bounds (3 > 2) in dimension 2

我可能在这里很傻,但是从阅读this 开始,我认为-Wno-array-bounds 应该抑制这个警告?使用-w 编译成功禁止所有警告。

我不知道这是否相关,但这些警告的来源是“Subprograms.f08”和“constitutive_models.f08”,它们都是包含子程序并在主程序中使用的模块。

如果我尝试用

编译单个模块,也会发生同样的行为
gfortran -Wno-array-bounds -c constitutive_models.f08 

【问题讨论】:

  • 在构建 gfortran 时将 -fbounds-check 设置为默认值是不常见的。您的编译时检查是一个不同的问题,您应该在源代码中修复。
  • 我没有构建 gfortran,我只是在 Ubuntu 16.04 上使用 sudo apt-get install gfortran 安装了它。当然,这表明源代码一定有问题。我会尝试删除 gfortran 并重新安装它 - 这没有任何区别。
  • 它可能不会在编译时抑制检查。边界检查总是很好用,除了增加运行时间。编译器和计算机现在这么快,为什么还要担心编译时间增加?
  • 如果在开发过程中经常使用边界检查、初始化变量检查和未使用的变量检查。一旦您进行了单元测试,或者针对一些给出预期结果的标准运行,代码就会在没有这些检查的情况下重新编译,并确认“正确性”的最终验证。然后使用 -O2、-O3 等发布生产代码。当然希望纠正越界问题,而不仅仅是禁用边界警告。
  • 我编写了一个代码,它可以在 1、2 或 3 维中工作,具体取决于包含模拟参数的模块中的规范。因此,存在取决于所选维度数量的代码分支。因此,如果选择了较低的维度,则会在编译时生成警告。例如ELSEIF (dim==3) THEN particle_data(jj)%scnd_pk(dim-1,1) = particle_data(jj)%scnd_pk(1,dim-1) 如果dim=1 这会引发警告。

标签: gcc fortran compiler-warnings gfortran compiler-flags


【解决方案1】:

我可以用这个简单的代码确认 compile warning 与 gfortran (4.4):

 integer,parameter::dim=3
 integer :: x(2)
 if(dim.eq.1)write(*,*)x(dim)
 end

警告:(1) 处的数组引用在维度 2 中超出范围 (3 > 2)

这可以说是一个错误,因为人们希望编译器优化整个if 语句。注意 ifort 编译它就好了。

一个非常简单的解决方法修复了这个例子:

 integer,parameter::dim=3
 integer :: x(2),dimx=dim
 if(dim.eq.1)write(*,*)x(dimx)
 end

当然,因为它只是一个警告,而且你知道这不是问题,你也可以选择忽略它!

注意逻辑中参数的使用,以防编译器以后想优化它。

【讨论】:

  • 如果启用了绑定检查,Ifort 也会发出警告。
  • 问题是有很多警告似乎淹没了其他可能更险恶的警告。你的建议很好,帮助我删除了其中的大部分。
【解决方案2】:

所以我可能建议使用重载的子例程来处理数据 - 然后您将拥有通用行为,而无需将维度参数显式传递给函数(从而摆脱警告)。然后我建议您遵循 Holmz 的建议,即在测试阶段使用所有警告,然后在生产构建期间完全关闭它们 (-w)。现在我无法找到一种有效的方法来抑制这个警告(除了-w) - 似乎数组边界的检查默认情况下是打开的,并且没有被覆盖 -fno-bounds-check 或 -Wno-array -界限。但是重载函数可以更好地解决您的问题,在这种情况下实现应该如下所示:

module functions

    implicit none

    interface test_dim
        module procedure test_func1d, test_func2d, test_func3d
    end interface ! test_dim

    contains

    subroutine test_func1d(input1d)
        real, intent(in) :: input1d(:)

        print*, "DOING 1 DIM"
        print*, "SHAPE OF ARRAY:", shape(input1d)
    end subroutine test_func1d

    subroutine test_func2d(input2d)
        real, intent(in) :: input2d(:,:)

        print*, "DOING 2 DIM"
        print*, "SHAPE OF ARRAY:", shape(input2d)
    end subroutine test_func2d

    subroutine test_func3d(input3d)
        real, intent(in) :: input3d(:,:,:)

        print*, "DOING 3 DIM"
        print*, "SHAPE OF ARRAY:", shape(input3d)
    end subroutine test_func3d

end module functions

program test_prog
    use functions

    implicit none

    real :: case1(10), case2(20,10), case3(30, 40, 20)

    call test_dim(case1)
    call test_dim(case2)
    call test_dim(case3)
end program test_prog

这个函数产生的输出是这样的:

 DOING 1 DIM
 SHAPE OF ARRAY:          10
 DOING 2 DIM
 SHAPE OF ARRAY:          20          10
 DOING 3 DIM
 SHAPE OF ARRAY:          30          40          20

【讨论】:

  • 这是解决这类问题的标准做法吗?问题是代码很大,有超过 20-25 个子例程。你的建议基本上是这个数字的三倍,这意味着需要在 3 个不同的子程序中进行任何更改,这对我来说就像是灾难的秘诀!虽然如果这是一种常见的做法,那么我想这只是一个咬紧牙关做一个更好的程序员的问题。
  • 我不能肯定 - 我不知道你的问题。一般来说 - 是的。但是既然你提到你有很多子例程 - 这种方法可以修改。首先,所有这些子程序都有相似的签名吗?如果是 - 我会说这也可能是问题的潜在根源(至少它可能是混乱的根源)。如果不是 - 那么您可以尝试按签名对它们进行分组,为每个组创建界面。但是,如果您能更详细地描述您的问题 - 我可能会尝试提出一个具体的解决方案。
  • 接口也是类型安全的——如果你调用一个带有你没有实现的参数组合的函数——那么编译器会抱怨这个
  • 正如@Chaosit 所说,这很常见......但通常我发现它对函数而不是子例程更有效。由于没有可靠的例子,很难准确地说出。使用 DEC 扩展或 ifort 的一种方法是 UNION 和 MAP,然后您可以将 NxM 2D 数组寻址为 2D 或 1D (N*M)。指针是另一种选择,但它们对于向量化代码可能会带来更多问题。所以基本上这些函数,以及任何常用的子程序,可以有多个版本,如果它们在很多程序中使用,它们最好在一个库中使用。
猜你喜欢
  • 1970-01-01
  • 2011-08-01
  • 1970-01-01
  • 2011-08-31
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-22
相关资源
最近更新 更多