为什么在清楚地写入数组边界时没有运行时错误?

时间:2012-03-23 14:12:25

标签: fortran runtime-error range-checking

我有一个程序可以指定一个超出它界限的数组,我期待抛出一个运行时错误。然而,根本没有出现错误,程序继续写入未声明的内存。是否有一些编译器选项来防范这种情况?通过显示内存转储,很明显这种边界的超越是真实的。有没有办法声明变量或参数规范来捕获它?显然这是一个明显的案例,但是当负责维护数千行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,因为我知道我得到了它。

以下是运行时检查的编译器选项。 Compiler Options

Memory of <code>R</code> variable

2 个答案:

答案 0 :(得分:4)

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

$ ifort -O0 -debug -traceback -check -ftrapuv TEST_CODE.f90

您将收到运行时错误。但对于假定大小的数组,intel编译器无法检查边界。特别是对于具有隐式类型的F77代码等,它很容易找到内存泄漏。另一件小事,在Fortran你的程序必须做一些有意义的事情;否则编译器会省略你的代码,因为它什么都不做!这就是我最后添加印刷品的原因。

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

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

答案 1 :(得分:3)

有趣。 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)或(*)的过程参数或多个维度中的一个或多个相同。