2012-03-23 14 views
5

Mam program, który przypisuje tablicy poza jej granicami i oczekiwałem, że zostanie zgłoszony błąd podczas wykonywania. Jednak w ogóle nie popełniono błędu, a program zapisuje się w pamięci nierejestrowanej. Czy jest jakaś opcja kompilatora, aby się przed tym zabezpieczyć? Po wyświetleniu zrzutu pamięci jasne jest, że ten nadmierny zasięg jest prawdziwy. Czy istnieje sposób na zadeklarowanie zmiennych lub specyfikacji argumentów, aby to złapać? Oczywiście jest to oczywisty przypadek, ale kiedy ma się utrzymywać tysiące linii kodu pochodzącego z F77, nie zawsze jest jasne (dla mnie), czy to się dzieje.Dlaczego nie występuje błąd środowiska wykonawczego, gdy wyraźnie zapisuje się na granicach tablicy?

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 

kompilator Intel Fortran 2011 XE, i tak używam spec bajtowy INTEGER*4 bo wiem, co mam z nim.

Oto opcje kompilatora do sprawdzania czasu wykonywania. Compiler Options

Memory of <code>R</code> variable

Odpowiedz

4

Kompilator intel wykonuje bardzo dobre zadanie sprawdzania granic dla wskaźnika i alokacji tablic. Jeśli nieco zmodyfikować kod (poniżej) i skompilować z czymś takim:

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

dostaniesz błąd czasie wykonywania. Ale dla założonych układów wielkości kompilator intel nie może sprawdzić granic. Szczególnie w przypadku kodów F77 z niejawnym pisaniem i tak dalej, nie będzie łatwo znaleźć wycieki pamięci. Kolejna drobna sprawa, w Fortranie twój program musi zrobić coś znaczącego; w przeciwnym razie kompilator pominie twój kod, ponieważ po prostu nie robi nic! Dlatego dodałem wydruk na końcu.

Jest mały problem z R (:) chodzi o to, że kompilator nie może założyć, że jest przyległy do ​​pamięci; dlatego nie może zoptymalizować optymalizacji kompilatora. Lepiej byłoby wtedy korzystać z alokowanych tablic lub użyć przylegającego atrybutu (standard 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

Dzięki za odpowiedź. Jeśli kompilator nie może przyjąć ciągłej pamięci, to w jaki sposób obsługuje indeksowanie tablicy. Czy nie każda tablica zwiększa się o stałą odległość od poprzedniej, tak jak z tablicami C? – ja72

+0

Nie, założone tablice kształtów, takie jak R (:), nie mają ciągłości. C nie ma tablic (wskaźniki nie są liczone!). Istnieją jednak metody w C do tworzenia ciągłych wskaźników tablicy (zobacz http://stackoverflow.com/questions/5196318/reallocation-of-contiguous-2d-array). W Fortranie możesz to sprawdzić po prostu. Testowałem i uzyskuję 10-15% wzrost wydajności, gdy używam atrybutu allocatable. Kiedy wykonujesz mieszane programowanie C/Fortran, możesz odwzorować R (:) na tablicę wskaźników typu C. –

3

Interesujące. gfortran 4.6 znajduje błąd indeksu środowiska wykonawczego:

At line 18 of file test_code.f90 
Fortran runtime error: Index '5' of dimension 1 of array 'r' above upper bound of 1 

, ale nie XF 12.1.1.246 nie.

EDYCJA: oto odpowiedź z dokumentacji kompilatora Intela: "Dla tablic, które są atrapami, tylko dolna granica jest sprawdzana dla wymiaru, którego górna granica jest określona jako * lub gdzie górne i dolne ograniczenia są zarówno 1 . " A kiedy deklaracja zostanie zmieniona na R (2), ifort znajdzie także błąd w indeksie dolnym.

Powodem tego jest to, że wiele starych kodów użyło wartości "1" dla wielkości atrapowej tablicy argumentów, aby wskazać nieznany rozmiar. Działa to, jeśli argument jest traktowany jako adres, ale oczywiście uniemożliwia sprawdzenie indeksu, ponieważ kompilator nie zna wielkości atrapa. Techniki tej nie należy stosować w nowym kodzie. Fortran 90 zapewnia lepsze opcje, np. Macierze o założonym kształcie (deklaracja dwukropka).

Tak więc odpowiedź na "nie zawsze jasne (dla mnie), jeśli to może się dziać", tj. Gdy twój starszy kod nie jest sprawdzany przez ifort - szukał argumentów procedury zadeklarowanych jako (1) lub (*) lub taki sam dla jednego lub więcej z wielu wymiarów.

+0

W jaki sposób zmuszasz gfortran do sprawdzania ranfe? Zawsze używam valgrind lub Solaris Studio. Wiele razy sprawdzałem opcje debugowania. –

+0

Co to jest sprawdzanie _ranfe_?:-) – ja72

+0

Opcje kompilatora debugowania dla gfortran, których używam, są w stylu Unix/Mac: -O2 -fimplicit-none -Wall -Wline-truncation-Character-truncation -Wsurprising -Waliasing -Wimplicit-interface -Wunused-parameter - fwhole-file -fcheck = all -std = f2008 -pedantic-fbacktrace. Mogą generować wiele ostrzeżeń przy użyciu starego kodu, więc może być konieczne usunięcie niektórych. –

Powiązane problemy