2011-05-29 15 views
10

To najbardziej dziwna rzecz, jaka mi się przydarzyła podczas programowania w C++.Błąd, który znika podczas próby studiowania.

To jest mój główny plik:

#include <iostream> 
#include "lib/utils.h" 

using namespace std; 

int main(int argc, const char *argv[]) { 
    cout << bin2dec(101000010); 
    return 0; 
} 

a to lib/utils.cpp:

#include <iostream> 
#include "utils.h" 

int bin2dec(int bin) { 
    // 101000010 
    int dec; 
    //std::cout << ""; // If you uncomment this, it works. 
    for (int i = 1; bin > 0; i *= 2, bin /= 10) { 
     if (bin % 2 == 1) { 
      dec += i; 
     } 
    } 
    return dec; 
} 

Program kompiluje bez ostrzeżenia, a kiedy uciekać, wyprowadza 450. 450 to nie 101000010 w systemie dziesiętnym, 322 to. Pierwszą dziwną rzeczą jest to, że różnica między 482 a 322 wynosi dokładnie 128. Dzieje się tak z każdą liczbą binarną, którą próbujesz przekonwertować. Ale to, co jest NAPRAWDĘ dziwne, polega na tym, że kiedy próbowałem wyprowadzić wartość bin i dec wewnątrz for w celu debugowania funkcji, nagle zaczęło działać poprawnie.

Zasadniczo, z jakiegoś powodu, jeśli przed powrotem funkcja powróci, zadziała. Jeśli nie, dodaje 128 do wyniku.

używam g ++ 4.6.0 i kompilacji tak:

g++ -c -D NDEBUG -O2  -o 10.o 10.cpp 
g++ -c -D NDEBUG -O2  -o lib/utils.o lib/utils.cpp 
g++ -o 10 -Wl,-S 10.o lib/utils.o lib/menu.o 
+0

+1 za dobrze zadane pytanie –

+0

Jest to niezwykle powszechne - witamy w świecie niezdefiniowanych zachowań. –

+0

@Doug Być może możesz mi wyjaśnić, na czym polega pytanie? –

Odpowiedz

23

Nie inicjalizujesz dec.

int dec = 0; 
+0

Bzdura, zapomniałem. Teraz czuję się jak idiota. No cóż. Dzięki! –

+2

@Gerado nie powinieneś: P Błędny błąd, tym bardziej "głupi" na błąd, który popełniłeś: P wszyscy już tam byliśmy, i wszyscy znowu tam jesteśmy – Wipqozn

0

Całkiem po prostu, problem krzyczy stos lub sterty rozbijając do mnie- prawdopodobnie komin, ponieważ wszystkie operacje są na funkcji stos. Nie dostaniesz się do tego rodzaju problemu bez wywoływania nieprzyjemnego niezdefiniowanego zachowania w innym miejscu programu.

Edytuj: O tak - możesz zacząć od zainicjowania dec, tylko na przykład.

3
int dec; 

Tworzy dec ale nie daje mu wartość początkową (jak 0). Następnie dodajesz do niego wartości, a kończy się losowym wynikiem.

3

Trzeba zainicjować dec do zera w funkcji:

int dec = 0; 

By nie inicjalizacji, to zaczyna się cokolwiek random CRUD w pamięci w miejscu zmiennej. A połączenie z cout << może wpłynąć na to, co jest na tym obszarze, stąd zmiany. Przy okazji, kiedy wypróbowałem twój kod, nie otrzymywałem 450. Otrzymałem 134514688 co daje przykład tego.

16

Niewielki błąd polega na tym, że nie inicjalizujesz zmiennej dec.

Większy błąd polega na tym, że podczas kompilacji nie dodaje się -Wall i -O2 (coś, co spowoduje wiele bólu, ponieważ programy, które piszesz, staną się bardziej złożone).

-Wall włącza wszystkie ostrzeżenia i -O2 wymaga optymalizacji (optymalizacja obejmuje analizę ścieżki kodu, która podniesie ostrzeżenia o niezainicjowanych zmiennych).

+2

Pokonaj mnie. Zawsze używaj -Wall. Czasami -Wall to za mało. Kompilacja z opcją -Wall i optymalizacją pozwoli na znalezienie niezainicjowanych zmiennych. –

+0

@David Hammen: True ... żądanie optymalizacji jest ważne, aby zobaczyć więcej ostrzeżeń. Zmieniono moją odpowiedź. – 6502

+0

Ściana * nie * włącza wszystkich ostrzeżeń. Istnieje sporo ostrzeżeń, że -Wall nie łapie. Używam -Wall -Wold-style-cast -Woverloaded-virtual-Wshadow. Dodałbym -Wffff ++ do miksu, gdyby nie to, że generuje dużo hałasu z implementacji standardowej biblioteki GNU. –

Powiązane problemy