Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Język C. Level: zielony - obliczanie temperatury

Jakub17 09 Aug 2016 17:23 1425 6
  • #1
    Jakub17
    Level 6  
    Witam.

    Zacząłem się uczyć języka C. Mam prosty program do przeliczania temperatur (wiem że można było to zrobić prościej ale lecę z książką i wykonuje ćwiczenia pod każdym rozdziałem).

    Code: c
    Log in, to see the code



    Otóż wszystkie wartości celsius wyświetlane są jako 0.0 dla każdej wartości fahr. Jeżeli zmienię typ zmiennej celsius na int to wszystko jest ok, tylko wyniki są niedokładne bo zaokrąglane do liczb całkowitych. Dlaczego tak się dzieje, że na float to nie działa?
  • Helpful post
    #3
    Krzysztof Gustaw
    Level 23  
    Witam!
    Jeśli definiowana funkcja nie jest poprzedzona typem, wówczas kompilator przyjmuje, że zwraca wartość typu int. Ponadto w funkcji main, funkcja obliczanie_temp jest wywoływana przed jej definicją, a nie po. W tym przypadku musi w funkcji main lub przed nią wystąpić deklaracja potwierdzająca (prototyp).
    Kolejne niedopatrzenie - zmienna celsius nie jest zainicjowana. istnieje możliwość, że pętla for może się nie wykonać ani razu. Jaka wartość w tym przypadku zostanie zwrócona przez funkcję obliczanie_temp ?
    I tak na przyszłość, lepiej stałe zmiennoprzecinkowe wypisywać w postaci np 1.0, 5.0 czyli:
    zamiast:
    Code: c
    Log in, to see the code

    pisać w sposób:
    Code: c
    Log in, to see the code

    Dla kogoś analizującego program od razu będzie wiadomo o ich zmiennoprzecinkowej naturze a kompilator na pewno pójdzie tym śladem.
    Pozdrawiam
    KG
  • Helpful post
    #4
    JacekCz
    Level 39  
    w printf znak procent jest znakiem specjalnym, pierwszy wiersz jest niewłaściwy. Jak wszystko w C efekt jest Undefined Behaviour czyli błąd ale czasem może działać.

    Jak chcesz świadomie drukować % to dwa razy %%, ale nigdy tego nie robię. - do drukowania bez formatowania są prostsze, szybsze funkcje jak puts itd...

    Wywód o niezadeklarowanych typach jest prawidłowy, zrób jak piszą. Czytam wielokrotnie, nie rozumieniem po co pętla for dla przeliczenia jednostek, może w geście rozpaczy próba uzyskania "jakiegoś" wyniku.

    Na liście printf nie ma jakiegoś językowego bezpiecznika, tylko programista odpowiada by na %f pasowała wartość dokładnie float (tzn nawet nie double). Wynik pomieszania to znów UB, trochę zadziała na jednej architekturze, zupełne czary na innej itd... gdyby funkcja obliczanie_temp się przyjęła jako int, będą znaczne problemy z %f.
  • Helpful post
    #6
    JacekCz
    Level 39  
    Jakub17 wrote:
    A jakie są praktyczne konsekwencje nie zastosowania prototypu? Bo bez niego czy z nim program działa tak samo.


    W pierwszych słowach powtórzę mocno, w programowaniu w językach "kod maszynowy" a zwłaszcza w C są liczne sytuacje, że błąd na razie się nie ujawnia. Standard mówi o tym słowami Undefined Behaviour, ludowa mądrość programistów o "parzystej ilości błędów" które się nie ujawniają.

    Brak prototypu wprowadza dwie główne sytuacje:
    a) domniemanie 'int' jako typu zwracanego
    b) potem rzutowanie o ile "lewa strona" jest znana. Wyjątkiem dla rzutowania są argumenty rzeczywiste funkcji o zmiennej ilości argumentów (var args) jak rodzina printf.
    c) nieokreślona lista argumentów (z braku prototypu) tez podlega domniemaniom. Szczerze: nie mam w głowie jak standard mówi. realne kompilatory jakoś tam. Mocno niebezpieczne.

    Pomylenie zmiennego przecinka na architekturach bez koprocesora (gdzie jest przekazywany zawsze na normalnym stosie) przynajmniej daje jakiś obszar komórek pamięci który jest "jakoś" wypełniony, tj nie są to przypadkowe wartości, w tym zdarzy się część zerowych bajtów.
    Na architekturach z koprocesorem bywa że FP jest przekazywany zupełnie inaczej, biorca oczekuje na "zwykłym stosie" i jest mocna sieczka.

    Pomylenie krótkich/długich typów integerowych często pozornie się uda, że problem pozamiata się pod dywan.

    Generalną zasadą nowszych wersji C jest ograniczenie możliwości użycie bez prototypu, od ostrzeżeń aż do błędu w C++.

    Drugie, co można sobie strzelić, to prototyp w soursie C, po jakimś czasie developowania w drugim module jest inny prototyp itd... niby prototyp jest, warningu nie ma, ale d/d. Kompilator C tego problemu nie wykryje.

    Ja w praktyce zawsze zakładam własny header i włączam go w modułach C.
    Już pominę że większość u mnie to mniej czy bardziej standardowe C++
  • #7
    Jakub17
    Level 6  
    Dzięki za wyczerpującą odpowiedź. Udało się poprawić kod i wszystko działa. A co do prototypu to mimo że Twój wykład jest bardzo wnikliwy i obejmuje zagadnienia których na razie w pełni nie rozumiem, to przydał się. Mianowicie punkt a) konsekwencji "Braku prototypu [...]" pomógł mi rozwiązać problem. Zapodałem typ funkcji obliczanie_temp jako float i dodałem na początku prototyp typu float i działa. Bez prototypu ani rusz, sypało błędy, także jeszcze raz dzięki.