2012-03-23 23 views
5

我有一個程序,它分配一個超出它的邊界的數組,我期待一個運行時錯誤被拋出。然而,沒有任何錯誤發生,程序繼續寫入未聲明的內存。有沒有一些編譯器選項來防止這種情況發生?顯示內存轉儲清楚地表明這種邊界的超越是真實的。有沒有辦法聲明變量或參數規格來捕捉這個?顯然這是一個明顯的例子,但是當要維護數千行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

回答

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 
+0

感謝您的回答。如果編譯器不能承擔連續內存,它如何處理數組索引。是不是每個數組都增加一個固定的距離,比如前面的一個,就像C數組一樣? – ja72 2012-03-27 17:18:39

+0

不,像R(:)這樣的假定形狀數組不能保證是連續的。 C沒有數組(指針不計數!)。雖然,C中有方法來創建連續的數組指針(請參閱http://stackoverflow.com/questions/5196318/reallocation-of-contiguous-2d-array)。在Fortran中,你可以簡單地測試它。我測試過,當我使用allocatable屬性時,性能提升了10-15%。當你混合使用C/Fortran編程時,你可以將R(:)映射到C類型的指針數組。 – 2012-04-18 12:23:20

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)或(*)的過程參數, )或對於多個維度中的一個或多個維度相同。

+0

你如何強制gfortran做ranfe檢查?我總是必須使用valgrind或Solaris Studio。我多次查看調試選項。 – 2012-03-23 15:41:27

+0

什麼是_ranfe_檢查?:-) – ja72 2012-03-23 15:43:50

+0

我使用的gfortran的調試編譯器選項是Unix/Mac風格:-O2 -fimplicit-none -Wall -Wline-truncation -Wcharacter-truncation -Wsprising -Waliasing -Wimplicit-interface -Wunused-parameter- fwhole-file -fcheck = all -std = f2008 -pedantic -fbacktrace。這些可能會在舊代碼中產生很多警告,因此您可能需要刪除一些代碼。 – 2012-03-23 16:12:28

相關問題