2010-08-20 4 views
11

Następujący kod testowy działa poprawnie w VS z debugowaniem lub wydaniem, a także w GCC. Działa również poprawnie dla ICC z debugowaniem, ale nie wtedy, gdy włączona jest optymalizacja (-O2).Czy kompilatory mogą usuwać nieskończone pętle, takie jak kompilator Intel C++ z opcją -O2?

#include <cstdio> 

class tClassA{ 
public: 
    int m_first, m_last; 

    tClassA() : m_first(0), m_last(0) {} 
    ~tClassA() {} 

    bool isEmpty() const {return (m_first == m_last);} 
    void updateFirst() {m_first = m_first + 1;} 
    void updateLast() {m_last = m_last + 1;} 
    void doSomething() {printf("should not reach here\r\n");} 
}; 

int main() { 
    tClassA q; 
    while(true) { 
    while(q.isEmpty()) ; 
    q.doSomething(); 
    } 
    return 1; 
} 

Ma się zatrzymać pod adresem while(q.isEmpty()). Jednak gdy opcja -O2 włączona pod ICC (release), nieskończenie zaczyna "robić coś".

Ponieważ jest jednowątkowy Program iisEmpty() należy ocenić jako true mogę znaleźć żadnego powodu MTK powinien zachowywać się w ten sposób? Czy coś mi brakuje?

+0

to pomoże, jeśli m_first i m_last są zadeklarowane jako 'lotny'? Nie mam dostępu do ICC. – Chubsdad

+0

Kolejna szalona myśl: ma to związek z tym, że% s nie jest określony przez printf. printf ("% s", "nie powinno tu dotrzeć \ r \ n") ;? – Chubsdad

+5

Powiązane: [Czy kompilatory mogą eliminować nieskończone pętle?] (Http://stackoverflow.com/questions/2178115/silniki-zablokowane-to-eliminate-infinite-loops) –

Odpowiedz

0

Najlepiej jest pobrać wynikowy krok binarny i zdekompletować główną funkcję i sprawdzić, jaki zestaw został wygenerowany. Nie mówiąc, że będziesz mógł zobaczyć błąd, ale możesz zobaczyć, czy coś zostało zoptymalizowane.

+0

Nie możesz. Kod asm jest zoptymalizowany od wszystkiego i nic nie widać. – Samuel

+0

Nie jestem pewien, co to oznacza. Mówisz, że zdemontowałeś wynikowy plik binarny, a pętla while() zniknęła? – linuxuser27

2

To na pewno brzmi jak błąd. Oto (dość dzikie) odgadnąć o co rozumowanie może mieć przewagę do niego ...

Po inline, to widzi:

while (q.m_first == q.m_last) /* do nothing */ ; 
do_something(); 

i każda sekwencja do nothing repeatedly ; do something można przetłumaczyć po prostu „coś zrobić”. Spada, jeśli powtarzająca się część jest nieskończona (jak w tym przypadku). Być może jednak nie testują swoich kompilacji na przykładach, które celowo mają nieskończoną pętlę ;-).

+0

Wykrywanie celowego nieskończonego zapętlenia jest w zasadzie problemem zatrzymania, więc zamiast tego zakłada, że ​​ponieważ nie ma widocznych efektów ubocznych, nie robi nic i dlatego jest bezużyteczny dla programu i może zostać usunięty. Oczywiście, niezależnie od tego, czy jest on kompletny, czy nie, jest widoczny dla nas efekt sde, ale nie dla maszyny abstrakcyjnej C/C++ zdefiniowanej przez standard. Jeśli potrzebujesz pętli, musisz powiedzieć kompilatorowi, że tak naprawdę wpływa na program, wykonując exmaple jedną z zmiennych odczytu volatile – Dan

-3

Myślę, że to mogła być Twoja wersja gcc. Skompilowałem program w wersji 4.4.2 i działało dokładnie tak, jak powinno.

+2

To jest icc, nie gcc –

1

Czy istnieje szansa, że ​​kod, który zbudowałeś i przebiegłeś, nie zawierał średnika po while(q.isEmpty())? To z pewnością spowodowałoby, że następna linia byłaby nazywana nieskończenie.

+0

+1 za przypomnienie mi czegoś podobnego – Chubsdad

+0

1. tam jest średnik 2. taki sam wynik z while (q.isEmpty()) {}, lub while (q.isEmpty()) {true;} – Samuel

+0

Do kogo: Czy głosowanie było naprawdę konieczne? Widziałem wiele przypadków na SO, gdzie opublikowany kod nie był dokładnym użytym kodem i gdzie rzeczywisty problem został pominięty lub poprawiony w tłumaczeniu. Chciałem tylko upewnić się, że nie wynika to z prostego, ale łatwego do pominięcia błędu. (W końcu, czy nie wszyscy traciliśmy czas na błąd z powodu czegoś w rodzaju pomyłkowego średnika?). – TheUndeadFish

10

Ponieważ pętla while (q.isEmpty()) ; nie zawiera żadnych instrukcji, które mogą kiedykolwiek powodować efekt uboczny widoczny z zewnątrz, cała pętla jest zoptymalizowana. To z tego samego powodu, że:

for (int i = 0; i < 10; i++) 
    ; 

mogą być optymalizowane z istnieniem, tak długo, jak nie było volatilei (przechowuje do volatile obiekty są częścią „widoczny z zewnątrz” efektów programu).

W języku C jest to w rzeczywistości znakomita kość niezgody co do tego, czy nieskończona pętla może być zoptymalizowana w ten sposób (nie wiem, jaka jest sytuacja z C++). O ile mi wiadomo, nigdy nie osiągnięto konsensusu w tym zakresie - mądrzy i kompetentni ludzie zajęli obie strony.

+0

To może być powód. Następujący kod działa poprawnie: static int A = 0; while (q.isEmpty()) {A = A + 1;} Ale nie następujące: static int A = 1; while (q.isEmpty()) {A;} – Samuel

+1

Interesujące. Nieskończona pętla nic nie robi - dobra szansa na optymalizację (i jest zrozumiałe, dlaczego ktoś może się z tym nie zgodzić). – Suma

+0

Jeszcze jedno: jeśli podczas gdy (prawda) jest używany podczas gdy (q.isEmpty()), kod działa poprawnie. – Samuel

1

Jak na marginesie, ta wersja icc robi to, co chcesz. Oznacza to, że nigdy nie wywołuje doSomething().

[9:41am][[email protected] /tmp] icc --version 
icc (ICC) 11.0 20081105 
1

standardem C++ pozwala pętle bez skutków ubocznych zostać usunięte, nawet jeśli nie kończą:

Powszechnie uważało, że jest ważne, aby umożliwić przekształcenie potencjalnie nie kończące się pętle (np. poprzez połączenie dwóch pętli, które iterują nad tym samym potencjalnie zestawem nieskończonym, lub poprzez wyeliminowanie pętli nie wymagającej efektów ubocznych ), nawet jeśli ta nie może być w inny sposób usprawiedliwiona w W przypadku, gdy pierwsza pętla nigdy nie kończy się . http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm

Zobacz dyskusję tutaj: http://blog.regehr.org/archives/161