Fortran 为什么在明确写入数组边界时没有运行时错误?

Fortran 为什么在明确写入数组边界时没有运行时错误?,fortran,runtime-error,range-checking,Fortran,Runtime Error,Range Checking,我有一个程序,它分配的数组超出了它的边界,我希望抛出一个运行时错误。然而,不会产生任何错误,程序继续写入未声明的内存。是否有一些编译器选项可以防止这种情况?随着内存转储的显示,很明显,这种越界是真实的。有没有一种方法可以声明变量或参数规范来捕捉这种情况?显然,这是一个明显的例子,但是当任务是维护数千行F77派生代码时,并不总是清楚(对我来说)是否会发生这种情况 PROGRAM TEST_CODE IMPLICIT NONE INTEGER*4 :: R(5) ! Array

我有一个程序,它分配的数组超出了它的边界,我希望抛出一个运行时错误。然而,不会产生任何错误,程序继续写入未声明的内存。是否有一些编译器选项可以防止这种情况?随着内存转储的显示,很明显,这种越界是真实的。有没有一种方法可以声明变量或参数规范来捕捉这种情况?显然,这是一个明显的例子,但是当任务是维护数千行F77派生代码时,并不总是清楚(对我来说)是否会发生这种情况

PROGRAM TEST_CODE
IMPLICIT NONE

INTEGER*4 :: R(5)           ! Array of 5

    CALL R_TEST(R, 10)

END PROGRAM

SUBROUTINE R_TEST(R, J)
IMPLICIT NONE

INTEGER*4, INTENT(INOUT) :: R(1)    ! Dummy is array of 1
INTEGER*4, INTENT(IN) :: J
INTEGER*4 :: K

DO K=J-5,J+5            ! K=5..15
    R(K) = K            ! No Runtime Error
END DO

END SUBROUTINE
编译器是英特尔Fortran 2011 XE,是的,我使用的是字节规范
INTEGER*4
,因为我知道它能带来什么

以下是用于运行时检查的编译器选项。


R变量“>

有趣。gfortran 4.6查找运行时下标错误:

At line 18 of file test_code.f90
Fortran runtime error: Index '5' of dimension 1 of array 'r' above upper bound of 1 
但ifort XE 12.1.1.246没有

编辑:以下是英特尔编译器文档中的答案:“对于伪参数数组,仅检查上界指定为*或上下界均为1的维度的下界。”当声明更改为R(2)时,ifort也会发现下标错误

原因是很多旧代码使用了“1”值“用于指示未知大小的伪参数数组的大小。如果您只是将参数视为地址,那么这是可行的,但是由于编译器不知道伪参数的大小,因此不可能进行任何下标检查。新代码中不应使用此技术。Fortran 90提供了更好的选项,例如,假定形状数组(冒号声明)


因此,“不总是清楚(对我来说)是否会发生这种情况”,即当ifort未检查您的遗留代码时——查找声明为(1)或(*)的过程参数,或一个或多个多维的过程参数。

英特尔编译器在指针和可分配数组的边界检查方面做得非常好。如果您稍微修改代码(如下)并使用以下内容进行编译:

$ifort-O0-调试-回溯-检查-ftrapuv测试\ U代码.f90

您将得到一个运行时错误。但对于假定大小的数组,“英特尔编译器”无法检查边界。特别是对于带有隐式类型等的F77代码,查找内存泄漏并不容易。另一件小事,在Fortran中,你的程序必须做一些有意义的事情;否则编译器将忽略您的代码,因为它什么也不做!这就是为什么我最后加了一张照片

R(:)有一个小问题,编译器不能假设它在内存中是连续的;因此,它不能进行一些编译器优化。然后最好使用可分配数组或连续属性(F2008标准)


你是如何强迫gfortran做ranfe检查的?我总是要使用valgrind或Solaris Studio。我研究了很多次调试选项。我使用的gfortran的调试编译器选项是Unix/Mac风格的:-O2-fimplicit none-Wall-Wline truncation-Wcharacter truncation-Wsurprising-Waliasing-Wimplicit interface-Wunused参数-fwhole file-fcheck=all-std=f2008-pedantic-fbacktrace。这些可能会对旧代码产生大量警告,因此您可能需要删除一些。ranfe可能在范围内。gfortran-fcheck=all contains-fcheck=bounds。谢谢,有趣的是,我使用了
-fbacktrace-ggdb-pedantic-Wall-fcheck=all-ffpe trap=zero,overflow
,它可以在我现在尝试的简单测试用例上工作,但我真的记得它在我的大型程序中不起作用。谢谢你的回答。如果编译器不能假定连续内存,它将如何处理数组索引。不是每个数组的增量都与前一个数组的增量保持固定的距离,就像C数组一样吗?不是,像R(:)这样的假定形状数组不能保证是连续的。C没有数组(指针不被计数!)。不过,C中有一些方法可以创建连续数组指针(请参阅)。在Fortran中,您可以简单地测试这一点。我进行了测试,当我使用可分配属性时,性能提高了10-15%。在进行C/Fortran混合编程时,可以将R(:)映射到C类型指针数组。
PROGRAM TEST_CODE
IMPLICIT NONE

INTEGER*4 :: R(5)           ! Array of 5

    CALL R_TEST(R, 10)
    print *,R

END PROGRAM

SUBROUTINE R_TEST(R, J)
IMPLICIT NONE

INTEGER*4, INTENT(INOUT) :: R(:)    ! Dummy is array of 1
INTEGER*4, INTENT(IN) :: J
INTEGER*4 :: K

DO K=J-5,J+5            ! K=5..15
    R(K) = K            ! No Runtime Error
END DO

END SUBROUTINE