Почему нет ошибки времени выполнения при четкой записи за границы массива?
У меня есть программа, которая назначает массив за его пределами, и я ожидал, что будет выдана ошибка во время выполнения. Тем не менее, никаких ошибок не возникает, и программа переходит к записи в необъявленную память. Есть ли какая-то опция компилятора, чтобы защититься от этого? С показанным дампом памяти ясно, что это превышение границ реально. Есть ли способ объявить переменные или спецификации аргумента, чтобы поймать это? Очевидно, что это очевидный случай, но когда ему поручено поддерживать тысячи строк кода, производного от 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
Компилятор - Intel Fortran 2011 XE, и да, я использую спецификацию байта INTEGER*4
потому что я знаю, что я получаю с этим.
Вот параметры компилятора для проверки во время выполнения.
R code">
2 ответа
Компилятор intel отлично справляется с проверкой границ для указателей и выделяемых массивов. Если вы немного измените свой код (ниже) и скомпилируете что-то вроде:
$ ifort -O0 -debug -traceback -check -ftrapuv TEST_CODE.f90
вы получите ошибку во время выполнения. Но для массивов предполагаемого размера компилятор Intel не может проверить границы. Особенно для кодов F77 с неявной типизацией и т. Д. Будет нелегко обнаружить утечки памяти. Еще одна крошечная вещь: в Фортране ваша программа должна делать что-то значимое; в противном случае компилятор пропустит ваш код, потому что он просто ничего не делает! Вот почему я добавил печать в конце.
Существует небольшая проблема с 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
Интересно. 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 этого не делает.
РЕДАКТИРОВАТЬ: вот ответ из документации компилятора Intel: "Для массивов, которые являются фиктивными аргументами, проверяется только нижняя граница для измерения, верхняя граница которого указана как * или где верхняя и нижняя границы равны 1". И когда объявление изменяется на R(2), ifort также находит ошибку в индексе.
Причиной этого является то, что во многих старых кодах для массива фиктивных аргументов используется значение "1", указывающее на неизвестный размер. Это работает, если вы просто рассматриваете аргумент как адрес, но, конечно, делаете невозможной любую проверку индекса, потому что компилятор не знает размер фиктивного аргумента. Эта техника не должна использоваться в новом коде. Fortran 90 предоставляет лучшие варианты, например, массивы предполагаемой формы (объявление двоеточия).
Таким образом, ответ на вопрос "не всегда ясно (для меня), может ли это происходить", т. Е. Когда ваш устаревший код не проверяется ifort - искал аргументы процедуры, объявленные как (1) или (*), или же для одного или нескольких из нескольких измерений.