Debugging Fortran程序中的混淆调试错误

Debugging Fortran程序中的混淆调试错误,debugging,gdb,fortran,memory-address,Debugging,Gdb,Fortran,Memory Address,我坐在这里已经有一段时间了,对于为什么我的调试器在程序运行正常时仍在代码中显示错误感到困惑。一个非常简单的程序有三个部分,它只是从文件中读入信息 我的代码被分解成下面给出的三个Fortran文件,并通过 ifort-o测试全局.f90读取.f90测试.f90 global.f90: module global implicit none integer(4), parameter :: jsz = 904 end module global 阅读.f90: subroutine rea

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

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

ifort-o测试全局.f90读取.f90测试.f90

global.f90:

module global
  implicit none
  integer(4), parameter :: jsz = 904
end module global
阅读.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
断点1,读取(kp=904,
q=,
wt=…,swt=6.9531436082559572e-310)在读数处。f90:6
调用
read
的子例程时,此错误正确显示。换句话说,我在
read
子例程中添加了一个断点,并在添加断点后在gdb中运行代码。当我在“测试”程序中包含write语句时,程序将继续按预期运行并给出正确的输出。但是,如果我使用gdb打印选项,我只会收到数组
q
的“无法访问地址0x69bb80处的内存”错误。可以毫无问题地显示所有其他数组和变量

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


如果您能深入了解此错误的可能原因,或提出尝试解决内存寻址问题的建议,我们将不胜感激。

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

我认为这是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)
$cat test.f90
子程序条(arg)
整数,意图(inout)::arg
打印*,“条形参数为”,参数
arg=42
结束子程序条
程序测试
整数::参数
参数=3
呼叫栏(参数)
打印*,“post bar参数:”,参数
结束程序测试
$ifort-g-O0-o测试.f90
$gdb—安静测试
从/home/nrath/tmp/test读取符号…完成。
(gdb)b 4
0x402bd0处的断点1:文件test.f90,第4行。
(gdb)r
启动程序:/home/nrath/tmp/test
[已启用使用libthread_db的线程调试]
test.f90:4处的断点1,bar(arg=@0x2aa00000003)
4打印*,“条形参数为”,arg
(gdb)p arg
$1=(参考->(整数(4))@0x2AA00000003:
(gdb)退出
$gdb——版本|头-1
GNU gdb(gdb)Red Hat Enterprise Linux(7.2-60.el6_4.1)

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

您使用的编译器是什么,我只是在Mac OSX中的英特尔编译器上编译了代码,没有出现问题?如果您使用的是gfortran编译器,我经常会遇到使用gfortran编译器重新编译最初在英特尔编译器上开发的代码的问题。从这个问题可以看出,他使用的是
ifort
。正如弗拉基米尔所提到的,我实际上使用的是英特尔编译器。我相信它是Fedora 19上的13版,gdb版本是7.6.1-42。再加上我最后的评论,我刚刚在两台不同的计算机上编译过,都是ifort 13.0.0 20120731和Fedora 19。但是,调试器在7.6.1-42和7.6.1-46中有细微差别。如果我将文件分开或将其设置为单个文件,则会出现相同的错误。这不是真的。显式接口(不是
接口
块)有时是必要的,但在这种情况下并非如此。模块几乎总是比
接口
块更好的选择。然而,用户试图调用的函数不是模块的一部分,而是单独文件中的一个子例程。如果子程序是外部的,因此不是模块或主程序的一部分,则需要
接口,而不是。标准中有这样的条件。我将检查接口选项,但我以前从未遇到过这个问题,过去也从未使用过接口。几乎我所有的代码都是以单个文件的形式编写的,可以通过上面给出的一行代码,也可以通过makefile进行编译。您不必执行接口块,只需将子例程移动到模块中即可获得更好的效果。它可能什么也治不好。我试过了,但我一开始就不明白你原来的错误。顺便说一句,将所有内容都放在一个大文件中是可以的,至少对于测试来说是这样。您还可以使用
ifort
选项
-warn interfaces
查看接口是否可能存在问题。