logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[A32] [A32][C] Pętla while z dwoma warunkami zawiesza program - jak to naprawić?

hessuss 12 Cze 2012 13:41 1912 17
  • #1 10993427
    hessuss
    Poziom 13  
    Czołem, napisałem sobie funkcję która wyświetla mi czas odpytując RTC, ale jak ktoś wciśnie na klawiaturze 'Esc' to wychodzi z pętli prezentującej czas i to dział bez zastrzeżeń ( całą noc od wczoraj )
    dziś stwierdziłem, że wprowadzę dodatkową zmienną o nazwie konfig.
    Zmienne mam w pliku gównym zadeklarowane tak :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod



    w pliku konfiguracja_pst.h mam tak :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    w konfiguracja_ps2.c taka funkcja siedzi :

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    w ten sposób wszystko się kompiluje i działą cała noc jak wspomniałem.
    Ale jak w warunku while chiałem zrobić żeby sprawdzał czy klepnięto esc na klawiaturce czy wprowadzono w inny sposób modyfikację wartości zmiennej konfig to wyświetlacz pokazuje mi czas i sekundnik stoi, normalnie idzie w krzaki.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Może mi ktoś podpowiedzieć gdzie robię błąd?
    Pewnie coś pokrzaczyłem w deklaracji tych zmiennych globalnych :/
  • #2 10993590
    mmacura
    Poziom 18  
    A nie powinno być przypadkiem tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #3 10993926
    hessuss
    Poziom 13  
    No właśnie nie, warunek :
    Pętlij się dopóty, dopóki wartość zmiennej konfig będzie równa 0x01 oraz dopóki ktoś nie naciśnie Esc czyli znak==0x76
    chodzi o to żeby na bieżąco odczytywało z RTC wskazanie zegara i aktualizowało to na wyświetlaczu.
    Problem zniknął gdy zmienną 'i' która była extern zamieniłem na zmienną 'g' tworzoną wewnątrz funkcji w pierwszej linijce
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    chciałem zrobić to na globalnych żeby nie obawiać się tworzenia nieograniczonej ilości zmiennych które mogły by zapełnić pamięć powodując zawieszenie procesora. Z tego co się doczytałem zmienne tworzone w funkcji "giną" w raz z wyjściem z funkcji ale jak to jest naprawdę?? Czy nie zależy od kompilatora i jego ustawień??
    W dalszym ciągu nie rozumiem dlaczego program zachował sie tak jak to opisałem.
    Będę wdzięczny za sugestie, bo to, że to moja wina nie ulega wątpliwości.
  • Pomocny post
    #4 10994131
    stanleysts
    Poziom 27  
    Cytat:
    Z tego co się doczytałem zmienne tworzone w funkcji "giną" w raz z wyjściem z funkcji ale jak to jest naprawdę??


    Radzę znaleźć jakąś dobrą książkę do C.
    W skrócie: takie zmienne (automatyczne) giną ponieważ przechowywane są w trakcie wykonywania danej funkcji na stosie. Jeśli program wchodzi w nową funkcję na stosie zapisywany jest kontekst powrotu do funkcji wraz wartościami rejestrów (mi. wartość licznika program counter (PC)) następnie na stosie lądują zmiennie z tej funkcji i na nich tam się odbywa zabawa do momentu powrotu z funkcji (kiedy ze stosu sciągany jest kontekst).

    Cytat:
    Czy nie zależy od kompilatora i jego ustawień??


    Zdecydowanie nie.

    Nie działało Ci najprawdopodobniej dlatego, że wartość tej zmiennej globalnej zmieniała się niespodziewanie (nie wiem co ona robila i po co dawales jej volatile). W każdym razie jak sobie zrobiłeś w tej funkcji zmienną g i przypisałeś pod jej adres wartość z modułu RTC no to na tej wartości Ci działała funkcja bcd2dec. A jeśli pracowałeś na zmiennej i, no to już na przykład przypisałeś jej wartość zero, ona zmieniła nagle wartość i tą dziwną wartość zacząłeś modyfikować w funkcji bcd2dec.
  • #5 10995951
    hessuss
    Poziom 13  
    Czyli rozumiem, że mogę sobie wywoływać funkcję w której tworzę jakąś zmienną tak jak w tym przypadku nawet i milion razy a i tak nie musze się obawiać tak zwanego "wycieku pamięci" bo przy wyjściu z funkcji kompilator sam zadba by ją ubić w sensie zwolnić pamięć?
    I idąc dalej tym tokiem rozumowania w mojej poprzedniej konstrukcji jakimś dziwnym cudem działo sie tak jakby zmienna tworzyła się przy każdej pętli i nie ubijała, mimo że była extern volatile a może właśnie dlatego ?
  • #6 10996563
    stanleysts
    Poziom 27  
    Cytat:
    Czyli rozumiem, że mogę sobie wywoływać funkcję w której tworzę jakąś zmienną tak jak w tym przypadku nawet i milion razy a i tak nie musze się obawiać tak zwanego "wycieku pamięci" bo przy wyjściu z funkcji kompilator sam zadba by ją ubić w sensie zwolnić pamięć?


    Nie do końca o to chodzi, niby operacja na zmiennych automatycznych nie powoduje wycieku pamięci, ale to pojęcie jest związane raczej z dynamiczną alokacją danych. Ale nie masz sie czego obawiać, bo wywołanie funkcji nigdy nie powoduje gromadzenia się zmiennych automatycznych w pamięci bo tak jak mówisz one są po wyjściu z funkcji usuwane.

    Cytat:
    I idąc dalej tym tokiem rozumowania w mojej poprzedniej konstrukcji jakimś dziwnym cudem działo sie tak jakby zmienna tworzyła się przy każdej pętli i nie ubijała, mimo że była extern volatile a może właśnie dlatego ?


    Nie, tłumaczyłem Ci o co mogło chodzić, i to nie jest tak jak myslisz, zmienna "i" to jest globalna jest stworzona raz i jest dostępna w wybranym zakresie w trakcie działania programu. Ona się nie tworzy kilka razy (zmiana wartości nie oznacza, że powstała nowa zmienna), to że była extern to dlatego mogłeś z niej korzystać w pliku, w którym nie była zdefiniowana, a volatile też z żadnym tworzeniem nie ma nic wspólnego, polecam przeczytać na spokojnie książkę do C.
  • #7 10996824
    gaskoin
    Poziom 38  
    Generalnie nie da się zrobić wycieku pamięci nie używając funkcji malloc.

    Żeby stwierdzić co było nie tak musiałbyś wrzucić cały kod, bo to co wrzuciłeś ma pewnie mało z nim wspólnego. I pisałem już milion razy - zmiennych globalnych trzeba unikać gdzie tylko się da. Jeśli musisz coś robić ze zmienną napis to wkładaj ją lokalnie dla funkcji poprzez wskaźnik, bo kod jest mega nieczytelny i trudny w analizie.
  • #8 10997414
    hessuss
    Poziom 13  
    Wskaźniki, no pewnie, tylko jak w takim razie zrobić tak, że jest sobie funkcja wyświetlająca i zmienna napis[], i robimy :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    i funkcja wyświetl, wyświetla ten napis,
    a teraz chciałbym żeby ta funkcja wyświetliła tekst który jej podam z ręki
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    to kompilator będzie sie czepiał, że chce wskaźnik, to jak mu go podać? Utworzyć tymczasową zmienną, do niej załadować ten tekst "z ręki" i podać wskaźnik? to się mija z celem bo i tak tworzę zmienną i tak. Oczywiście podając tekst z ręki nie chcę zmieniać zawartości zmiennej napis[].
  • #9 10997467
    stanleysts
    Poziom 27  
    Nie ma czegoś takiego:

    &napis[]

    Mówie weź książkę do C, bo tak to nigdzie nie zajedziesz bez podstaw.

    Możliwe są deklaracje:

    char * napis = "Przeczytaj jakąś książkę do C" ;

    i sobie potem tym wskaznikiem skaczesz zeby wyswietlic co chcesz(masz tu prosty kod - tak to działa):

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #10 10997570
    tmf
    VIP Zasłużony dla elektroda
    Tylko weźcie pod uwagę, że to AVR, napisy jako stałe autor zapewne chce mieć we FLASH, a nie w SRAM, stąd też trzeba się zaprzyjaźnić z pgmspace.h i PSTR. Ale to dopiero jak się poczyta o podstawach C :)
    Aha, jeszcze jedno BTW :) W avr-gcc nie działa merge-consts i merge-strings, stąd też trzeba troszkę uważać i niestety zmienne globalne czasami są konieczne.
  • #11 10999639
    hessuss
    Poziom 13  
    Stanleysts -> jak nie ma jak jest.
    Do nauki C korzystałem z tutoriala XIONA który jest powszechnie uznawany w necie za jeden z lepszych. W temacie wskaźniki było tak :
    Cytat:

    // deklaracja zmiennej typu int oraz wskaźnika na zmienne tego typu
    int nZmienna = 10;
    int* pnWskaznik; // nasz wskaźnik na zmienne typu int
    // przypisanie adresu zmiennej do naszego wskaźnika i użycie go do
    // wyświetlenia jej wartości w konsoli
    pnWskaznik = &nZmienna; // pnWskaznik odnosi się teraz do nZmienna
    std::cout << *pnWskaznik; // otrzymamy 10, czyli wartość zmiennej

    i w związku z powyższym chyba nie mamy nic do zarzucenia?
    Teraz piszemy kod funkcji:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    i teraz chcemy sobie wywołać taką funkcję korzystając z uprzednio zadeklarowanej tablicy char
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    teraz chcę podać tą zmienną do w/w funkcji, musze podać nie zmienną a wskaźnik więc czy nie mogę po prostu w wywołaniu funkcji zastosować przypisania adresu zmiennej w formie
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    u mnie się to kompiluje i działa.
    czy musze najpierw utworzyć wskaźnik a potem podać funkcji tenże wskaźnik tak :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    można by się było zastanawiać czy &napis[0] czy &napis[] ale czy to nie to samo? wszak oba zapisy wskazują na adres tablicy, nieprawdaż?
    PS.
    Używam AVR Studio 4 ( mam stk 500 i AVR Studio 5 nie chce mi z nim gadać)

    TMF -> robię coś a'la menu na drukarkach, zegarek + konfigurowanie go z klawiatury PS2. Czasem na wyświetlaczu mam odczytaną godzinę a podczas konfiguracji napis "data" lub "godzina" stąd tejże funkcji czasem musze podać zwykły tekst i chciałbym ją wywoływać jakoś tak :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #12 10999683
    tmf
    VIP Zasłużony dla elektroda
    Widzisz, tak to jest z tutorialami w necie, że nawet jak są dobre to nie poruszają wszystkich kwestii. Jednak co książka to książka, więc weź pod uwagę wcześniejsze sugestie kolegów. Generalnie tablice są zawsze przekazywane jako wskaźniki, de facto nazwa tablicy jest wskaźnikiem. Stąd też twoja konstrukcja &napis[] jest co najmniej dziwna. Masz też błąd w definicji napis - literał "Napis" ma 5 znaków (bajtów), tablica napis tak samo, nie ma więc miejsca na terminator NULL, w efekcie łańcuch ten nie jest w formacie NULLZ, w efekcie jak twoja funkcja wyświetlająca ma się domyślić kiedy jest jego koniec? Pamiętaj też o modyfikatorach np. const - zapewne nic tego napisu nie ma zmieniać, więc lepiej dodać const uchar. Im więcej przekażesz informacji kompilatorowi, tym lepiej będzie on wiedział o co ci chodzi i pomoże ci uniknąć błędów.
  • #13 10999709
    gaskoin
    Poziom 38  
    "napis" jest typu char *
    podobnie jak char napis[] = "napis" też jest char *.

    Ten tutorial xiona jest do C++ a nie do języka C. Do C nie znalazłem nic sensownego na necie, poza wikibook. Jak już ktoś napisał - nazwa tablicy jest wskaźnikiem na jej pierwszy element a nie jakieś &tab[]. To działa, ale dlatego, że kompilator się domyśla o co Ci chodzi. O dziwo czasami i &tab zadziała :) Ale nie należy tego w żaden sposób wykorzystywać.
  • #14 10999991
    stanleysts
    Poziom 27  
    Cytat:
    Stanleysts -> jak nie ma jak jest.


    Masz mądry kompilator
  • #15 11000456
    hessuss
    Poziom 13  
    Tmf -> czy kompilator nie uzupełni tej tablicy o NULL na końcu jeśli zmienną deklaruję w ten sposób? Wydaje mi się, że powinien.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Gaskoin -> czyli, jeżeli funkcja czeka na wskaźnik a chcę jej podać tablicę to w tym przypadku prawidłowym wyjściem jest? Poniższe rozwiązanie kompiluje się i działa, pytam czy jest to zgodne ze sztuką:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #16 11000875
    tmf
    VIP Zasłużony dla elektroda
    Tak, uzupełni automatycznie, o ile ma miejsce. Jeśli napis ma 5 liter, a tablica 5 elementów to nic nie uzupełni bo nie ma na to miejsca.
    Co do drugiego pytania - tak - jest to poprawne, gdyż jak wspominałem (i kolega Gaskoin) identyfikator tablicy jest wskaźnikiem.
  • Pomocny post
    #17 11001097
    stanleysts
    Poziom 27  
    Cytat:
    Gaskoin -> czyli, jeżeli funkcja czeka na wskaźnik a chcę jej podać tablicę to w tym przypadku prawidłowym wyjściem jest? Poniższe rozwiązanie kompiluje się i działa, pytam czy jest to zgodne ze sztuką:


    Czytaj dokładniej co się do Ciebie pisze, specjalnie podałem Ci mały programik, w którym taka konstrukcja jest właśnie pokazana, jakbyś na niego popatrzył i odpalił, to być wiedział :D
  • #18 11001444
    hessuss
    Poziom 13  
    No i wyjaśnili mi panowie kwestie. Dzięki bardzo. Zamykamy kramik.
REKLAMA