2014-07-22 8 views
6

Oto fragment kodu z GNU C reference manual Pg 74:Gdzie jest drugi przelew w tym kawałku kodu

Jeśli kod wykorzystuje podpisaną indeksu pętli, upewnij się, że indeks nie może przelewowy, wraz z wszystkie podpisane wyrażenia wyprowadzone z indeksu. Oto przykładowy kod źródłowy z dwoma wystąpieniami przepełnienia .

for(i = INT_MAX - 10 ; i <= INT_MAX; i++) 
    if(i+1 < 0) //first overflow 
    { 
     report_overflow(); 
     break; 
    } 

Ze względu na dwa przepełnienia, kompilator może zoptymalizować dala lub przekształcenia dwóch porównań w sposób, który jest niezgodny z zawijanym założeniu.

+2

Czy możesz wyjaśnić nieco więcej, jakie jest twoje pytanie? – Sorcrer

+0

Drugim może być 'i <= INT_MAX; i ++ ' –

+1

' i <= INT_MAX' jest zawsze prawdziwe, więc pętla nigdy nie może przestać istnieć – mvp

Odpowiedz

4

Co oznacza GNU C reference manual oznacza, że ​​masz dwa możliwe przepełnienia. Pierwszy z nich to stwierdzenie w

for(i = INT_MAX - 10 ; i <= INT_MAX; i++) 

i++ a drugi byłby i+1 w

if(i+1 < 0) //first overflow 

Kod Przykład C unika wieczną pętlę z

if(i+1 < 0) //first overflow 
{ 
    report_overflow(); 
    break; 
} 

części kodu i aby to zrobić, polegasz na podpisanym zachowaniu.

Jednak dodatek A.3 mówi, że użytkownik nie powinien polegać na podpisanym zachowaniu, ponieważ optymalizator wykorzystuje jego niezdefiniowane zachowanie i może wygenerować kod, który zachowałby się inaczej niż oczekiwano. Tak jest w przypadku kodu if(i+1 < 0), który polega na tym, że zawijanie stanie się, gdy i jest INT_MAX.

Podsumowując, powyższy kod może się nie udać po zoptymalizowaniu przez kompilator.

+2

+1 Prawidłowo mówisz "nie powinieneś polegać na zachowaniu", być może ważne jest stwierdzenie, że tak jest, ponieważ zmienna jest podpisana, podczas gdy warunek jest gwarantowany, jeśli zmienna jest niepodpisana. – Antonio

+0

@Antonio: na wszystkich znanych architekturach nastąpi ominięcie * niezależnie * zmiennej sygnatury – mvp

+2

@mvp Chodzi o to, że optymalizator, bardziej niż architektura, może wywoływać "dziwne" zachowanie podczas polegania na zawijaniu przy użyciu podpisanej liczby całkowitej. Jest lepiej opisany w kilku wątkach, np. [1] (http://stackoverflow.com/a/7682539/2436175) [2] (http://stackoverflow.com/a/4240878/2436175) [3] (http://stackoverflow.com/questions/ 19842215/wrap-around-explanation-for-signed-and-unsigned-variables-in-c) – Antonio

2

Konwersja z komentarzem:

i <= INT_MAX jest zawsze prawdziwe, więc pętla nigdy nie można zamknąć. Jest to więc błąd, ponieważ przepełniają się i ++.

Ponieważ jest to zawsze prawda, kompilator może zoptymalizować ten warunek, co oczywiście nie jest oczekiwane.

+0

W kodzie napisanym jak jest, nie widzę, jak drugi przelew z powodu 'i ++' może wpłynąć na działanie i zmienić to w nieskończoną pętlę. Czy możesz mnie poprawić? – abc

+0

Spodziewasz się, że zwiększenie 'i' ostatecznie spowoduje przerwanie stanu pętli. Ale gdy i == INT_MAX, zwiększenie go jeszcze raz sprawia, że ​​jest ujemny (przepełnienie), więc twoje oczekiwania nigdy nie są spełnione, a pętla trwa na zawsze – mvp

+0

warunek pętli jest zepsuty przez klauzulę if. Czyż nie? – abc

2

ze względu na przerwę, nie powinno być żadnego
bez przerwy Byłoby wieczną pętlę, a przelew na ++i
od i <= INT_MAX jest prawdziwa dla wszystkich wartości i (zakładając i jest liczbą całkowitą)

Powiązane problemy