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

Poprawna budowa funkcji main w WinAVR

slawek55 27 Lut 2010 21:46 2082 18
  • #1 7760669
    slawek55
    Poziom 23  
    Cześć.
    nurtuje mnie taka sprawa.
    Pisząc program w WinAVR program powinien posiadać strukturę
    
    int main(void) {
    ...
    
    return 0;
    }

    Dlaczego piszemy return 0; skoro bez tego i tak działa? Nie generuje błędów ani ostreżeń. Działa również bez void w main, natomiast int musi sie pojawić.
    Skąd to się wzięło?

    Druga sprawa to zakończenie funkcji nie zwracającej wartości, czyli o budowie void funkcja(void)

    Czy poprawne jest zakończenie takiej funkcji instrukcją return; I czy jeśli funkcja ma skończyć się wcześniej np na podstawie jakiegoś warunku, czy mogę użyć return;

    Piszę o tym, nie dlatego że nie mogę sprawdzić ale dlatego czy to jest z formalnego punktu widzenia.
  • #2 7760714
    nenpa8lo
    Poziom 17  
    Sprawa historycznej wagi :-) z tym int main(void). Niektóre kompilatory nie mają problemu z void main(void) a niektóre wymagają int i zwrócenia wartości gdzieś w funkcji (korzenie pochodzą z programowania na PC gdzie program zwracał wartość do systemu - np. error, ok czy inne).

    Co do drugiego pytania, to jak najbardziej możesz zwrócić return; w funkcji typu void func(void). Dobry styl programowania skłaniał by się raczej do robienia jednego return na samym końcu funkcji, niż kilku w różnych miejscach (trudno potem debugować).
  • #3 7761144
    Freddie Chopin
    Specjalista - Mikrokontrolery
    nenpa8lo napisał:
    Dobry styl programowania skłaniał by się raczej do robienia jednego return na samym końcu funkcji, niż kilku w różnych miejscach (trudno potem debugować).

    Bzdura...

    Co łatwiej debugować?

    v1:
    if (!warunek_pierwszy)
    {
        ...
        if (!warunek_drugi)
        {
            ...
            if (!warunek_trzeci)
            {
                ...
                if (!warunek_czwarty)
                {
                    ...
                }
            }
        }
    }
    return;


    v2:

    if (warunek_pierwszy)
    return;
    
    ...
    if (warunek_drugi)
    return;
    ...
    if (warunek_trzeci)
    return;
    ...
    if (warunek_czwarty)
    return;
    ...
    return;

    ?

    Kod wynikowy w obydwóch przypadkach będzie identyczny.

    4\/3!!
  • #4 7761478
    oskar777

    Poziom 26  
    W C nie mam jeszcze doświadczenia ale w PHP opierającym się o C dawanie kilka return wcale nie daje identycznego efektu jak kilka IF. Dawanie kilka sztuk return robi niezły burdel, bo może doprowadzić do niecelowego / nieplanowanego opuszczenia funkcji przez to jak kolega wspomniał ciężej znaleźć błąd.
  • #5 7761804
    slawek55
    Poziom 23  
    Rozumem, a co z tym main? W kursie EdW też była o tym mowa i tam też dominowała forma int main(void){ ...... return0; }
    dlaczego to return 0; skoro bez tego jest OK?
  • #6 7762216
    tmf
    VIP Zasłużony dla elektroda
    Bo jesli funkcja zwraca int to nie moze byc samo return - kompilator wyrzuci blad. Musisz zwrocic cos co odpowiada deklaracji. BTW, w mikrokontrolerach funkcja main nie powinna sie nigdy konczyc - co procesor ma zrobic jesli wyjdziesz z main? Return z main stosuje sie tylko wtedy kiedy mamy jakis OS. Dlatego np. na AVR mozna przyoszczedzic troche pamieci stosujac definicje:
    void main(void) __attribute__((noreturn));
            
    void main(void)
    {
    }


    Wtedy main jest void a kompilator wie, ze nie ma z niej powrotu, dizeki czemu moze sobie podarowac tworzenie epilogu.
  • #7 7763905
    nenpa8lo
    Poziom 17  
    Freddie Chopin napisał:
    nenpa8lo napisał:
    Dobry styl programowania skłaniał by się raczej do robienia jednego return na samym końcu funkcji, niż kilku w różnych miejscach (trudno potem debugować).

    Bzdura...

    Co łatwiej debugować?

    v1:
    if (!warunek_pierwszy)
    {
        ...
        if (!warunek_drugi)
        {
            ...
            if (!warunek_trzeci)
            {
                ...
                if (!warunek_czwarty)
                {
                    ...
                }
            }
        }
    }
    return;


    v2:

    if (warunek_pierwszy)
    return;
    
    ...
    if (warunek_drugi)
    return;
    ...
    if (warunek_trzeci)
    return;
    ...
    if (warunek_czwarty)
    return;
    ...
    return;

    ?

    Kod wynikowy w obydwóch przypadkach będzie identyczny.

    4\/3!!
    Wg mnie obie wersje są błędne jeżeli masz kod V1 to powinieneś przemyśleć ten kawałek kodu.
    Osobiście zawsze staram się unikać takich konstrukcji kodu, i zawsze robię tylko jedno return w funkcji. Zbyt wiele razy musiałem borykać się z czyimś kodem pełnych retrunów tu i tam, i potem nie wiadomo o co chodzi, zresztą łatwiej też o błędy (po co sobie robić więcej roboty?).
  • #8 7764642
    tmf
    VIP Zasłużony dla elektroda
    Jak to nie wiedziales o co chodzi? Przeciez jesli masz konstrukcje if costam return to latwo sie domyslec jak program dziala. Jesli masz zagniezdzone if else to jest masakra ze sledzeniem. Jakie konkretnie bledy moga wystapic przy wielokrotnym return?
  • #9 7765006
    slawek55
    Poziom 23  
    Tak tylko mi nie chodzi o przejrzystość kodu tylko poprawność zapisu. Bo bo rozumiem ze poprawne jest użycie kilku instrukcji return, zarówno w funkcji jak i w przewraniu.
    Np czy poniższe są poprawne:
    Dla przerwania
    
    ISR(jakiestam){
    pomocnicza++;
    if(pomocnicza<500)return;
    ....
    ....
    //ciąg dalszy np przy obsłudze LED
    }  //koniec przewania

    I na końcu tego nie musi być instrukcja return;, choć może, czy tak?


    teraz dla jakiejs funkcji
    
    int wynik(int zmienna){
    if(zmienna==10)return 10;
    if(zmienna==20)return20;
    ...
    } // ciekawe czy jak żaden warunek nie jest spełniony moze zabraknąć return?
    


    Pomijam cel takiego programu bo można inaczej np ze switch(..)


    Co do funkcji main to nie zgadza mi się tylko to że sprawdziłem i nie mozna napisać void main(..) bo zgłasz błąd musi być int main
    Natomiast działa tak samo z return jak i bez niego. I to mnie zastanawia, dlaczego tak forsowane jest return 0; skoro bez tego i tak działa?
  • #10 7765020
    nenpa8lo
    Poziom 17  
    Na przykład powiedzmy że w funkcji jest bałagan (tak nazywam kilka wyjść) i przed opuszczeniem funkcji jakaś zmienna powinna być modyfikowana.
    Jeżeli w jednym przypadku zapomnisz jej zmodyfikować to pozamiatane. Program działa jak trzeba.... do czasu gdy trafi w ten jeden return gdzie zmienna nie została zmodyfikowana i bum.
  • #11 7765186
    tmf
    VIP Zasłużony dla elektroda
    Slawek: Tak, ISR moze byc bez return na koncu, bo to jest funkcja void, gdyby byla zdefiniowana jaka fukcja zwracajaca jakas wartosc to kompilator wypisalby ostrzezenie. Wielkokrotne instrukcje return sa poprawne. Co do drugiego przykladu - na koncu musi byc return, inaczej dostaniesz ostrzezenie, bo kompilator nie bedzie wiedzial co zwrocic z funkcji, kiedy zaden z warunkow nie jest spelniony. A zwrocic cos musi bo tak jest zdefiniowana funkcja. W efekcie dostaniesz ostrzezenie, a funkcja zwroci zazwyczaj cos nieprzewidywalnego. Co do main z typem void to zdefiniuj ta funkcje tak jak pokazalem to bedziesz mogl zrobic void main(). Return 0 dla main zwykle dodaje sie dla poprawienia czytelnosci i usuniecia warninga, ktory by sie pojawil bez tego return. Jak pisalem bez OS nie ma najmniejszego sensu stosowanie return w main.

    nenpa8lo: A czym sie twoj przyklad rozni od sytuacji w ktorej masz wielokrotne zagniezdzone if i zapomniales zmodyfikowac jakas zmienna? A dodatkowo masz jeszcze sytuacje z warunkiem logicznym rozlozonym na kilka instrukcji if...
    Dodatkowo dla mnie jest czytelniejsze cos takiego:
    
    void test(void *ptr)
    {
    if(ptr==NULL) return;
    dalsza czesc funkcji z bezpiecznym wskaznikiem
    }
    

    niz:
    
    void test(void *ptr)
    {
     if(ptr)
      {
        tu operujemy na bezpiecznym wskazniku
      }
    
    a tu przez pomylke mozemy wstawic instrukcje, ktore beda wykonane nawet dla ptr==null, wykrzaczajac program
    
    }
    
  • #12 7766079
    Freddie Chopin
    Specjalista - Mikrokontrolery
    nenpa8lo napisał:
    Na przykład powiedzmy że w funkcji jest bałagan (tak nazywam kilka wyjść) i przed opuszczeniem funkcji jakaś zmienna powinna być modyfikowana.
    Jeżeli w jednym przypadku zapomnisz jej zmodyfikować to pozamiatane. Program działa jak trzeba.... do czasu gdy trafi w ten jeden return gdzie zmienna nie została zmodyfikowana i bum.

    Słyszałeś powiedzenie "wylać dziecko z kąpielą"? Powodem problemu będzie bałagan w funkcji, błędy w kodzie, a NIE wielokrotne użycie return... Pozbycie się wielokrotnych returnów nie rozwiązuje takiego problemu.

    I uwierz mi, że jak funkcja ma np 100 linijek, to użycie w niej 5 returnów jest lepsze niż 5 par nawiasów klamrowych i szukania potem "o co chodzi". A jeśli funkcja będzie miała 200 linijek i 15 returnów? 15 par nawiasów = 15 x wcięcie = (przy standardowym wcięciu = 4 spacje) 60 znaków wcięcia... Super wygodne i bardzo czytelne...

    4\/3!!
  • #13 7766371
    nenpa8lo
    Poziom 17  
    Freddie Chopin: Wg mnie funkcja nie powinna mieć więcej niż 40 linijek kodu (50 to max). "Preferuje klopsy nad Spaghetti." :-D

    Temat rzeka... Ja staram się pisać kod tak by zawsze odpowiadał standardom systemów krytycznych - IEC 61508.
  • #14 7766679
    Konto nie istnieje
    Poziom 1  
  • #15 7766737
    michalko12
    Specjalista - Mikrokontrolery
    atom1477 napisał:
    To napisz mi funkcję FFT mającą mniej niż 40 linijek.
    No dobra, niech będzie 50.

    Lepiej się nie zakładaj :D

    vvv; xxx; yyy; zzz; ...
  • #16 7766962
    hursamir
    Poziom 10  
    Z tym return to jest tak ze C zostal stworzony dla UNIX albo UNIX dla C (slowa geeka). Jesli piszesz w shellu i powiedzmy masz napisany skrypt to po zwrocie danej wartosci do OS w zaleznosci od skrytu mozesz zaczac nastepny program zalezny od tej wlasnie wartosci, dlatego jest mozliwe posiadanie kilku innych return (wartosci zwracanych przez return). Moja wiedza na temat prog. mC jest podstawowa ale nie widze tutaj mozliwosci uzycia return (sam nie uzywam i kompilator sie nie pluje - chyba zalezy od kompilatora).
  • #17 7767825
    Konto nie istnieje
    Poziom 1  
  • #18 7771632
    nenpa8lo
    Poziom 17  
    michalko12 i atom1477 - przecież takie bzdury piszecie, że normalnie ręce opadają :cry:
    Jaki problem napisać FFT w 40-50 liniach? Zamiast makaronu na 200 linii rozbijasz kod na bloki funkcyjne i masz elegancką funkcję 40-50 linii (albo dużo mniej) z której wołasz funkcje, która wykonuje jakiś tam kawałek roboty.

    Jak dla mnie makaron ma rację bytu na prockach z małą ilością RAM, gdzie z funkcji nie chcemy wołać kolejnych funkcji, żeby zbyt wiele na stos nie ładować.
  • #19 7771648
    Konto nie istnieje
    Poziom 1  
REKLAMA