Fortran程序中令人困惑的调试错误

Posted

技术标签:

【中文标题】Fortran程序中令人困惑的调试错误【英文标题】:Confusing debugging error in Fortran program 【发布时间】:2014-02-25 19:05:33 【问题描述】:

我已经坐在这里一段时间了,我很困惑为什么我的调试器在程序运行正常时总是在我的代码中显示错误。一个非常简单的程序包含三个部分,它只是从文件中读取信息。

我的代码被分解成下面给出的三个 Fortran 文件并通过编译

ifort -o test global.f90 read.f90 test.f90

global.f90:

module global
  implicit none
  integer(4), parameter :: jsz = 904
end module global

read.f90:

subroutine read(kp,q,wt,swt)
implicit none
integer(4) :: i, j
integer(4), intent(in) :: kp
real(8), intent(out) :: swt, q(kp,3), wt(kp)
swt = 0.0d0; q(:,:) = 0.0d0; wt(:) = 0.0d0
open(7,file='test.dat')
read(7,*) ! Skipping a line
do i = 1, kp
  read(7,1000)(q(i,j),j=1,3), wt(i)
  swt = swt + wt(i)
end do
close(7)
return
1000 format(3F10.6,1X,1F10.6)
end subroutine read

test.f90:

program test
use global
integer(4) :: i, j
real(8) :: tot, qq(jsz,3), wts(jsz)
call read(jsz,qq,wts,tot)
stop
end program test

我一直收到的错误是

Breakpoint 1, read (kp=904, 
q=<error reading variable: Cannot access memory at address 0x69bb80>,
wt=..., swt=6.9531436082559572e-310) at read.f90:6

read的子程序被调用时,就会出现这个错误。换句话说,我在read 子例程处添加一个断点,并在添加断点后在gdb 中运行代码。当我在“测试”程序中包含写入语句时,程序将继续按预期运行并给出正确的输出。但是,如果我使用 gdb 打印选项,我会收到“无法访问地址 0x69bb80 的内存”的错误,仅适用于数组 q。所有其他数组和变量都可以正常显示。

由于我希望read 子例程是一个独立的子例程并且不一定使用任何全局参数,因此我没有使用全局模块,而是将变量kp 调用到子例程中。我决定测试使用全局模块是否有帮助,如果我使用jsz 代替kp,我确实消除了错误。但是,由于这不是我对子例程的总体目标,我希望弄清楚如何在不使用全局模块的情况下解决这个问题。 (我也试过完全不使用全局,直接在test.f90程序中设置kp的参数变量,但这也会报错。)

任何有关此错误可能原因的见解,或尝试修复内存寻址问题的建议将不胜感激。

【问题讨论】:

你用的是什么编译器,我刚刚在Mac OSX的INTEL编译器上编译了代码没有问题?如果您正在使用 gfortran 编译器,我经常在重新编译最初在 INTEL 编译器上开发的代码时遇到问题。 从问题中可以看出他使用了ifort 正如 Vladimir 所提到的,我实际上使用的是 intel 编译器。我相信它是 Fedora 19 上的版本 13,gdb 版本是 7.6.1-42。 补充我的最后一条评论,我刚刚在两台不同的计算机上编译,都使用 ifort 13.0.0 20120731 和 fedora 19。但是,调试器略有不同 7.6.1-42 和 7.6 .1-46 为另一个。如果我将文件分开或将其设为一个文件,则会出现同样的错误。 【参考方案1】:

我认为这是 ifort+gdb 组合特有的问题,较新的 gdb 版本已修复。这是一个重现问题的较小示例:

$ cat test.f90 
  subroutine bar(arg)
    integer, intent(inout):: arg

    print *, 'bar argument is', arg
    arg = 42
  end subroutine bar

  program test
    integer:: param
    param = 3
    call bar(param)
    print *, 'post-bar param:', param
  end program test
$ ifort -g -O0 -o test test.f90
$ gdb --quiet test
Reading symbols from /home/nrath/tmp/test...done.
(gdb) b 4
Breakpoint 1 at 0x402bd0: file test.f90, line 4.
(gdb) r
Starting program: /home/nrath/tmp/test 
[Thread debugging using libthread_db enabled]

Breakpoint 1, bar (arg=@0x2aaa00000003) at test.f90:4
4       print *, 'bar argument is', arg
(gdb) p arg
$1 = (REF TO -> ( INTEGER(4) )) @0x2aaa00000003: <error reading variable>
(gdb) quit
$ gdb --version | head -1
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)

但是,如果您使用 gfortran 而不是 ifort 进行编译,或者如果您使用 GDB 7.7.1,则可以正常工作。

【讨论】:

【参考方案2】:

您是否在程序末尾添加了INTERFACE 语句? 当你调用程序中不包含的函数时,你需要它。

【讨论】:

这不是真的。有时需要显式接口(不是inteface 块),但在这种情况下不需要。模块几乎总是比interface 块更好的替代品。 然而,用户试图调用的函数不是模块的一部分,而是单独文件中的子例程。如果子程序是外部的,因此不是模块或主程序的一部分,则需要interface 不是。标准中有这方面的条件。 我会检查接口选项,但我以前从未遇到过这个问题,我过去从未使用过接口。几乎我所有的代码都是作为单独的文件编写的,并通过我上面给出的单行或通过 makefile 编译。 你不必做接口块,只需将子程序移到模块中以获得更好的效果。它可能不会治愈任何东西。我试过了,但我一开始没有得到你原来的错误。顺便说一句,将所有内容放在一个大文件中是可以的,至少用于测试。您也可以使用ifort 选项-warn interfaces 来查看接口是否可能存在问题。

以上是关于Fortran程序中令人困惑的调试错误的主要内容,如果未能解决你的问题,请参考以下文章

K&R 使用 gdb 调试时,echo 程序的解释令人困惑。怎么了?

尝试上传到 Cloudinary 时收到令人困惑的错误

从 Fortran 到 Linux 的退出代码

fortran调试断言失败怎么解决?

Fortran 程序在运行时崩溃

令人困惑的模板错误