Fortran数组运行时边界检查未触发的原因咨询
为什么你的Fortran程序没有报错?这是自动数组的特性!
你遇到的情况其实是Fortran标准(从Fortran 90开始)支持的**自动数组(Automatic Array)**特性,并不是编译器偷偷把它转成了可分配数组,你的理解偏差在于对Fortran数组声明规则的认知~
核心原因:自动数组允许运行时确定局部数组大小
在Fortran中,局部数组的大小可以由在数组声明时已经确定值的变量来指定,这类数组就叫做自动数组。你的代码里:
nod是全局变量,在调用mysubtest之前,主程序已经通过READ(*,*) nod读取了用户输入的值,所以进入子程序时nod的取值是明确的- 因此
REAL(kind=8) :: num(nod)是完全符合标准的自动数组声明,编译器会在子程序调用时,根据当时nod的值为num分配内存,退出子程序时自动释放
为什么-fcheck=all没检测到错误?
因为你的程序根本没有越界行为!数组num的大小确实是你输入的500000000,赋值num=9.9d0是对整个数组赋值,访问num(1)和num(nod)都是在数组合法范围内的操作,完全符合规则,所以编译器和运行时检查都不会报错。
不过这里有个额外的点:5亿个双精度元素(每个8字节)总共需要4GB内存,这么大的数组如果放在栈上很可能会栈溢出,但gfortran对于较大的自动数组,会自动分配到堆内存中,所以你的程序能正常运行。
自动数组 vs 可分配数组
你可能会好奇自动数组和显式声明的可分配数组有什么区别:
- 自动数组:只能是局部数组,大小在子程序入口时确定,整个子程序执行期间大小固定,不需要手动
ALLOCATE/DEALLOCATE - 可分配数组:可以是局部或全局数组,大小可以在程序运行时随时调整,必须显式调用
ALLOCATE分配内存,不再需要时调用DEALLOCATE释放
怎么验证你的初始预期?
如果想触发你预期的错误,可以修改代码,让nod在数组声明时是未定义的:比如把READ(*,*) nod移到mysubtest内部,在声明num(nod)之后再读取nod。这时候编译运行时,-fcheck=all就会检测到nod未定义的错误,因为数组声明时变量值未知。
你的测试代码
MODULE globaldata IMPLICIT NONE INTEGER nod END MODULE globaldata MODULE modtest USE globaldata IMPLICIT NONE CONTAINS SUBROUTINE mysubtest(dummy) IMPLICIT NONE INTEGER :: dummy REAL(kind=8) :: num(nod) dummy = 7 num = 9.9d0 write(*,*) dummy,num(1),num(nod),size(num) END SUBROUTINE mysubtest END MODULE modtest PROGRAM test USE globaldata USE modtest IMPLICIT NONE INTEGER dummy1 WRITE(*,*)"Give the value of nod:" READ(*,*) nod CALL mysubtest(dummy1) END PROGRAM test
内容的提问来源于stack exchange,提问作者Andreas
相关产品推荐
相关产品推荐

