Tak więc otrzymałem od valgrind jakąś tajemniczą wiadomość o niezainicjowanych wartościach i pozostaje tajemnicą, skąd się wzięła zła wartość.
Wydaje się, że valgrind pokazuje miejsce, w którym ostatecznie używana jest wartość zjednostkowana, ale nie źródło niezainicjowanej wartości.
==11366== Conditional jump or move depends on uninitialised value(s)
==11366== at 0x43CAE4F: __printf_fp (in /lib/tls/i686/cmov/libc-2.7.so)
==11366== by 0x43C6563: vfprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366== by 0x43EAC03: vsnprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366== by 0x42D475B: (within /usr/lib/libstdc++.so.6.0.9)
==11366== by 0x42E2C9B: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366== by 0x42E31B4: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366== by 0x42EE56F: std::ostream& std::ostream::_M_insert<double>(double) (in /usr/lib/libstdc++.so.6.0.9)
==11366== by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)
==11366== by 0x810B9F1: Snake::Snake::update() (snake.cpp:257)
==11366== by 0x81113C1: SnakeApp::updateState() (snakeapp.cpp:224)
==11366== by 0x8120351: RoenGL::updateState() (roengl.cpp:1180)
==11366== by 0x81E87D9: Roensachs::update() (rs.cpp:321)
Jak widać, robi się to dość tajemnicze… zwłaszcza, że kiedy mówi Class :: MethodX, czasami wskazuje prosto na ostream itp. Być może jest to spowodowane optymalizacją?
==11366== by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)
Właśnie tak. Czy jest coś, czego mi brakuje? Jaki jest najlepszy sposób na wyłapanie złych wartości bez konieczności uciekania się do bardzo długiej pracy detektywa printf?
Aktualizacja:
Dowiedziałem się, co było nie tak, ale dziwne jest to, że Valgrind nie zgłosił tego, kiedy po raz pierwszy użyto złej wartości. Został użyty w funkcji mnożenia:
movespeed = stat.speedfactor * speedfac * currentbendfactor.val;
Gdzie speedfac był zjednoczonym spławikiem. Jednak w tym czasie nie zostało to zgłoszone i dopiero gdy wartość ma być wydrukowana, że pojawia się błąd .. Czy istnieje ustawienie dla valgrind, aby zmienić to zachowanie?
Oznacza to, że próbujesz wydrukować / wyprowadzić wartość, która jest przynajmniej częściowo niezainicjalizowana. Czy możesz to zawęzić, aby dokładnie wiedzieć, jaka to wartość? Następnie prześledź swój kod, aby zobaczyć, gdzie jest inicjowany. Są szanse, że zobaczysz, że nie jest w pełni inicjalizowany.
Jeśli potrzebujesz więcej pomocy, opublikowanie odpowiednich sekcji kodu źródłowego może pozwolić komuś zaoferować więcej wskazówek.
EDYTOWAĆ
Widzę, że znalazłeś problem. Zwróć uwagę, że valgrind obserwuje skok warunkowy lub ruch w oparciu o zjednostkowane zmienne. Oznacza to, że wygeneruje ostrzeżenie tylko wtedy, gdy wykonanie programu zostanie zmienione z powodu niezainicjowanej wartości (np. Program przyjmuje inną gałąź w instrukcji if). Ponieważ faktyczna arytmetyka nie obejmowała warunkowego skoku ani ruchu, valgrind nie ostrzegł cię o tym. Zamiast tego propagował stan „niezainicjowany” do wyniku instrukcji, która go użyła.
Może się wydawać sprzeczne z intuicją, że nie ostrzega od razu, ale jak zauważył mark4o , robi to, ponieważ niezainicjalizowane wartości są używane w C przez cały czas (przykłady: wypełnienie struktur,
realloc()
wywołanie itp.), Więc te ostrzeżenia nie byłyby bardzo przydatne ze względu na fałszywie dodatnią częstotliwość.źródło