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

[AVR] [C/ogólnie] Wskaźniki

kazeciak 04 Mar 2010 19:47 6290 32
  • #1 7783837
    kazeciak
    Poziom 15  
    Witam!

    Napisałem już trochę programów w życiu, ale -aż wstyd się przyznać- do dzisiaj nie rozumiem roli jaką odgrywają wskaźniki, nie potrafię ich używać, nie wiem do czego one służą, czemu z nich korzystać itd.
    Czy ktoś może mi to wyjaśnić w jakiś prosty sposób ?
    Pozostanę wdzięczny -choć nie wiem jak będę mógł tą wdzięczność okazać :)

    Pozdrawiam,
    Marcin
  • #2 7784337
    michalko12
    Specjalista - Mikrokontrolery
    kazeciak napisał:
    Witam!

    Napisałem już trochę programów w życiu, ale -aż wstyd się przyznać- do dzisiaj nie rozumiem roli jaką odgrywają wskaźniki, nie potrafię ich używać, nie wiem do czego one służą, czemu z nich korzystać itd.
    Czy ktoś może mi to wyjaśnić w jakiś prosty sposób ?
    Pozostanę wdzięczny -choć nie wiem jak będę mógł tą wdzięczność okazać :)

    Pozdrawiam,
    Marcin

    Najpierw poczytaj sobie w necie o wskaźnikach, a potem zadawaj konkretne pytania jak czegoś nie będziesz rozumiał. Bo uwierz mi nikt nie będzie Ci pisał referatów na temat wskaźników tym bardziej że w necie na ten temat jest od ... i jeszcze trochę.
  • Pomocny post
    #3 7784384
    p_zag
    Poziom 14  
    Witam.
    kazeciak napisał:

    Napisałem już trochę programów w życiu, ale -aż wstyd się przyznać- do dzisiaj nie rozumiem roli jaką odgrywają wskaźniki, nie potrafię ich używać, nie wiem do czego one służą, czemu z nich korzystać itd.
    Marcin

    Wskaźniki - no cóż, to takie twory, które potrafią bardzo ułatwić życie (czytaj programowanie), albo doprowadzić załamania nerwowego.

    A oto materiał do analizy"
    
    Przekazanie parametru przez wskazanie na zmienną (wskaźnik) umożliwia dokonania modyfikacji tej zmiennej wewnątrz funkcji.
      Czyli do funkcji wkładamy przez parametr jakąś wartość, tam zostaje ta wartość przerobiona
      i po zakończeniu funkcji funkcja oddaje zmienioną wartość przez ten sam parametr
    
     void funkcja(typ_zmiennej *wartosc1, typ_zmiennej *wartosc2)
      {
       typ_zmiennej zmienna_pomocnicza =0;
       zmienna_pomocnicza =*wartosc1;
       *wartosc1=*wartosc2;
       *wartosc2=zmienna_pomocnicza;
      } //  wywolanie funkcji np.->   funkcja(&zmienna1, &zmienna2);
    
     Uwaga! po wykonaniu funkcji " funkcja(&zmienna1, &zmienna2) "
            "zmienna1" i "zmienna2" beda zmodyfikowane przez tą funkcje
          ("zmienna1" i "zmienna2" mają inną wartość przed funkcją i inną wartość po wykonaniu tej funkcji)
    
    //--------------------------------
     Kiedy wskażnik pokazuje już na konkretnie miejsce możemy odnieśćc się do tego obiektu na
     który on wskazuje, odczytać jego wartość, lub wpisać wartość pod wskazany adres.
     Podstawowa operacja na wskażniku jest wyłuskanie, czyli odwolanie się do obiektu
     wskazywanego przez wskażnik. Operacja ta nazywa się adresowaniem pośrednim.
     Operatorem adresowania pośredniego jest jednoargumentowy * zapisywana jako przedrostek.
    
     Zastosowana do wskażnika daje zawartość obiektu wskazanego przez ten wskażnik np.:
    
        unsigned char *wsk;            // tworzona zmienna jest zmienną wskaźnikową
        unsigned char inne_cos =0, cos =3;   // inne_cos i cos maja wartości dowolne dla zilustrowania przykładu
        wsk =&cos;                     // <-- Uwaga!!! wsk przechowuje adres zmiennej cos.
        inne_cos =*wsk;               // <-- inne_cos posiada wartość z pod adresu cos (czyli  inne_cos =3)
        *wsk =200;                     // <-- wstaw 200(wartość dowolna np.200) pod adres wskazywany przez zmienną wsk (czyli  cos =200)
    //-------------------------------- 
    

    A oto funkcje w których zastosowałem wskażniki
    
    void minusCzas(unsigned char *dziesiatki, unsigned char *jednosci)
     {
      signed char pomoc =*jednosci;
      if(!((*dziesiatki ==0) && (*jednosci ==0))) pomoc -=1;         
      if(pomoc ==-1)
       {
        pomoc =9;
        *dziesiatki -=1;
       }
      *jednosci =pomoc;
     } // wywolanie funkcji np.->   minusCzas(&wartosc1,&wartosc2);
    
    void plusCzas(unsigned char *dziesiatki, unsigned char *jednosci)
     {
      if(!((*dziesiatki ==5) && (*jednosci ==9))) *jednosci +=1;
      if(*jednosci ==10)
       {
        *jednosci =0;
        *dziesiatki +=1;
       }
     } // wywolanie funkcji np.->   plusCzas(&wartosc1,&wartosc2); 
    

    Jest to fragment kodu mojego zegara led ze strony:
    https://www.elektroda.pl/rtvforum/topic1338039.html
    A po za tym szukaj w internecie na pewno coś znajdziesz.
    Piotr
  • #4 7784477
    rpal
    Poziom 27  
    kolego mimo że odsyłają ciebie inni do literatury to powiem ci że wskaźnik to taki "obiekt" w którym znajduje się adres w którym są przechowywane dane. Róznica między zwykłą zmienną jest taka że ta "zwykła" zawiera konkretną daną.
    Dla przykładu jesl zmienna i=0; to w jakimś miejscu pamięci (w sumie nieważnie jakim) masz wartość 0. Natomiast jeśli uzywasz zmiennej i która wcześniej została zadeklarowana jako wskaźnik np. char *i; to tym samym gdzieś w pamięci zarezerwowałeś sobie obszar 2 bajtów w którym to będzie umiesczony adres innej zmiennej która przechowuje jakąś wartoś. Cały myk polega na tym że mozna zmieniać teraz ten adres gdzie są końcowe dane i tym samym za każdym razem odczytywać/zapisywać inne dane. nie wiem czy pojąłeś ? :)
  • #5 7784554
    janbernat
    Poziom 38  
    No, może tak.
    Każda zmienna w programie ma jakąś wartość.
    Ale każda z nich jest przechowywana w jakiejś komórce pamięci.
    Wskaźnik jest to adres tej komórki pamięci w której jest ta zmienna przechowywana.
    W językach wysokiego poziomu nie masz dostępu do adresu komórki.
    A w C- który jest nazywany czasem makroasemblerem- masz.
    A jak masz adres- to możesz zmienić zawartość tej komórki pamięci- czyli zmienić wartość zmiennej.
    Reguły zapisu i dostępu do zawartości tej komórki pamięci są dla mnie też skomplikowane i niezrozumiałe.
    Ale w małych procesorach możliwość dostępu do zawartości dowolnej komórki jest pożyteczna.
    Dlatego jest tyle kompilatorów C na mikrokontrolery.
    P.S.
    rpal ujął to krócej.
  • #6 7784622
    rpal
    Poziom 27  
    ja mogę to też ująć dydaktycznie :) czyli jak dla Jasia w szkole.
    załóżmy że mieszkamy razem i pożyczyłem od ciebie 100 PLN to każdy rozumie :)
    i umawiamy się że oddam tę stówe wsadzając do szuflady. Zatem jesli przyjąć że szuflada to zmienna, szuflada = 100. Ale ja jestem podłym dłużnikiem i doo szuflady wsadzam kartkę na której napisałem że twoja stówa jest w kieszeni mojej kapoty. Zatem zmienna szuflada warta jest tyle do zawartość mojej kieszeni. Wsadzę tam 100 PLN więc szuflada = 100 ale jak włożę 50 PLN to już szuflada = 50. taka to róznica miedzy zmienną a jej wskaznikiem :) :) :)
  • #7 7784872
    janbernat
    Poziom 38  
    No dlatego napisałem jak jest- a nie że nad tym panuję.
    Najpierw wskaźnik na jedną z 256 szuflad.
    W szufladzie są albo pieniądze- albo wskaźnik gdzie są- w kieszeni albo w szufladzie nr X.
    W szufladzie nr X jest wskaźnik na wskaźnik- pieniądze są w szufladzie X+16.
    W kieszeni jest wskaźnik że pieniądze są w drugiej kieszeni.
    Oczywiście wskaźnik na drugą kieszeń wcześniej zdefiniowany.
    I wtedy wiemy że C ma ogromne możliwości- ale my musimy nad tymi możliwościami zapanować- wypuściliśmy dżina z butelki.
  • #8 7784928
    rpal
    Poziom 27  
    E tam, Panie Janie, to całe piekno tego że sobie można tak manipulować w te czy tamtą stronę :) Innaczej ten avr byłby tylko nieco wiekszym kalkulatorem. Zamiast otwierać butelke i wypuszczać dżina może lepiej połknąć tego gina ? :)
  • #9 7785034
    janbernat
    Poziom 38  
    No tak- w przeszłości "popełniłem" kilka programików w C.
    I przeczytałem kilka książek.
    Może dlatego że zdałem sobie sprawę co to C może- okropnie się tego boję.
    No ale- może połknę wkrótce tego dżina.
    Ale nie gina- nie wolno.
    Im dalej od sprzętu- tym jestem głupszy.
  • #10 7785055
    kazeciak
    Poziom 15  
    Dziękuję za odpowiedzi, nie wszystko jest jeszcze dla mnie jasne, ale chyba zaczynam rozumieć zagadnienie. Proszę rzucić okiem na ten przykład i na jego podstawie określić czy "załapałem" czy może jednak nie do końca:

    
    --------------------------------
    get_data(int a , void(*wskaznik)(void))
        {
        (...);
        wskaznik();
        }
    
    void send_msg(void)
        {
        (...);
        }
    ---------------------------------
    
    get_data(sens_1 , send_msg) ;
    
    ---------------------------------
     



    Wydaje mi się, że taka operacja jest możliwa, zastanawiam się tylko nad korzyściami jakie z niej płyną, coś gdzieś dzwoni, ale jeszcze nie wiem który to kościół...


    EDIT:
    Oczywiście w tym przypadku wg mojego założenia miał to być wskaźnik na funkcję.
  • #11 7785130
    rpal
    Poziom 27  
    jeśli ci się o uda skompilować to będzie cud, bo takie przykłady jak ten są pełne błędów składniowych no chyba że to wycinek programu.
    może prostszy przykład:
    int main(void){
    unsigned char costam;
    unsigned char *ptr;
    unsigned char wynik=0;
    	// zmienna "wynik" ma wartość 0
    	// przypisanie wartości 12 do zmiennej "costam"
    	costam=12;
    	// dotąd wskaźnik ptr był nieokreślony
    	// ale teraz jest ustawiony na miejsce w pamięci które
    	// kompilator przypisał zmiennej "costam"
    	ptr=&costam;
    	// zmiana wartości zmiennej "wynik" teraz ma już 12 zamiast uprzedniej wartości 0
    	wynik=*ptr;
    	// inkrementacja wartości kryjącej się pod wskaźnikiem
    	*(ptr)+=1;
    	// niespodzianka po przypisaniu do zmiennej "wynik" wartości zmiennej "costam"
    	wynik=costam;
    	// zamiast spodziewanego 12 jest tam 13
    	// ot zagadka :)
    	// dlaczego to już kolega sam musi sobie wymysleć
    	return 1;
    }
    

    piszesz kolego o wskaźniku na funkcję coś mi się zdaje że się tobie to nieco poplątało. Bo oczywiście wskaźnik może byc ustawiony na funkcję ale jak piszesz w ogóle nie kumasz co to są wskaźniki więc uzywając slów "wskaźnik na funkcję" wybiegasz przed orkiestrę bo to inna para kaloszy, ale o tym jak przerobisz wskaźniki zmiennych :) Wskaźnik na funkcje to nic innego ja sterowanie przebiegiem programu z tą różnicą że kiedy robisz to w sposób "tradycyjny" musisz to zawrzeć w samej strukturze napisanego programu. Tym samym to co ci przyjdzie do głowy przelewasz na ekran i twój program działa tak jak to sobie obmysliłeś. Kiedy użyjesz wskaźników funkcji, twój program zacznie żyć "własnym życiem" bez uzywania takich słów jak , if,else,goto, ect...
    Piszesz sobie np. kilka funkcji lub procedur które mają jakieś tam zadanie, określasz do nich wskaźniki i np. zapisujesz je w tablicy. Kiedy jakaś zmienna przyjmuje określoną wartość z przedziału będącego rozmiarem tablicy, zamiast używać w.w. if, else albo case odwołujesz się po prostu do wskażnika funkcji zawartego w tablicy a program skacze do odpowiadającej jej funkcji lub procedury uzywając właśnie wskaźnika funkcji.
    Piwo sie należy :)
  • #12 7785172
    michalko12
    Specjalista - Mikrokontrolery
    kazeciak napisał:
    Dziękuję za odpowiedzi, nie wszystko jest jeszcze dla mnie jasne, ale chyba zaczynam rozumieć zagadnienie. Proszę rzucić okiem na ten przykład i na jego podstawie określić czy "załapałem" czy może jednak nie do końca:

    
    --------------------------------
    get_data(int a , void(*wskaznik)(void))
        {
        (...);
        wskaznik();
        }
    
    void send_msg(void)
        {
        (...);
        }
    ---------------------------------
    
    get_data(sens_1 , send_msg) ;
    
    ---------------------------------
     



    Wydaje mi się, że taka operacja jest możliwa, zastanawiam się tylko nad korzyściami jakie z niej płyną, coś gdzieś dzwoni, ale jeszcze nie wiem który to kościół...


    EDIT:
    Oczywiście w tym przypadku wg mojego założenia miał to być wskaźnik na funkcję.



    Prawie dobrze. Do zmiany wywołanie funkcji:

  • #13 7785209
    rpal
    Poziom 27  
    rozumiem że chodzilo o przekazanie jako parametr wartości wskaźnika a nie wartości zmiennej. to może być tak:
    void procedura(unsigned char *ptr){
    	*(ptr)=1;
    }

    jesli teraz przekażesz do procedury wskaznik a nie wartość to procedura ją obsluży a zmieniona wartość tego co ukrywa się pod wskaźnikiem będzie widoczna z miejsca z którego była wywołana w tym przypadku wczesniejsze "cośtam" zmieni się na 1. Poza tym kup sobie ksiązkę, czytaj i trenuj.
    Ale ja już ide spać.PZDR
  • #14 7785237
    kazeciak
    Poziom 15  
    Wskaźnik cały czas pokazuje na "costam" ? a więc po inkrementacji "wskaźnika" o jeden dokonaliśmy tego nie na nim, tylko na zmiennej na która wskazywał ?

    Co do mojego "programu" to oczywiście "wycinek" nawet nie tyle co z programu, co na szybkiego chciałem pokazać samą ideę. Pomijając brak main() itd. wydaje mi się, ze takie coś powinno działać jako wskaźnik na funkcję.

    Zastanawiają mnie jednak najbardziej korzyści z tego płynące. Wydaje mi się, że potrafię już użyć wskaźnika, tylko nie rozumiem po co miałbym to robić, że tak to brzydko ujmę.

    W tym kodzie który przedstawiłem wcześniej, faktycznie musiałbym powiększyć trochę ciało funkcji get_data gdyby założyć, że poza send_msg mogę chcieć wywołać inne funkcje, np send_gin ( :) ) i jeszcze parę innych. Wtedy w ciele funkcji get_data musiałby być np. warunek "if" sprawdzający przesłany parametr i na tej podstawie z ciała tej właśnie funkcji byłaby wywoływana dana funkcja (send_msg, send_gin itd)

    Czyli tak

    mamy 3 funkcje

    send_msg();
    send_gin();
    send_0_7L();

    i są one wywoływane z funkcji

    get_data();


    bez wskaźników, musiałaby ona wyglądać mniej więcej tak (jej wywołanie oraz sama funkcja)

    
     
    get_data(int x) // CIALO
    {
       if(x==1) send_msg();
       if(x==2) send_gin();
       (....itd...)
    }
    
    
    get_data(1); // WYWOLANIE
    
    



    a ze wskaźnikiem:

    
    get_data(void(*wskaznik)(void)) // CIALO
    {
       wskaznik();
    }
    
    
    
    get_data(send_msg); // WYWOLANIE
    
    


    Zgadza się ?
  • #15 7785256
    michalko12
    Specjalista - Mikrokontrolery
    kazeciak napisał:

    bez wskaźników, musiałaby ona wyglądać mniej więcej tak (jej wywołanie oraz sama funkcja)

    
     
    get_data(int x) // CIALO
    {
       if(x==1) send_msg();
       if(x==2) send_gin();
       (....itd...)
    }
    
    
    get_data(1) // WYWOLANIE
    
    



    a ze wskaźnikiem:

    
    get_data(void(*wskaznik)(void)) // CIALO
    {
       wskaznik();
    }
    
    
    
    get_data(send_msg) // WYWOLANIE
    
    


    Zgadza się ?


    Cytasz w ogóle to co się do ciebie pisze?

    
    get_data(void(*wskaznik)(void)) // CIALO
    {
       (*wskaznik)();
    }
    
    
    
    get_data(send_msg) // WYWOLANIE
    
    


    int *i;

    int x = 100;

    i jest wskaźnikiem na liczbe typu int.

    i= &x;
    i ma adres zmienne x

    *i++; x ma teraz wartość 101
    i++; i juz nie wskazuje na x tylko na jakąś inna nieokreśloną zmienną.

    Wikipedia i wskaźniki
  • #16 7785385
    kazeciak
    Poziom 15  
    W którym momencie napisałem że nie czytam ? odpowiedziałem na "zadanie" które Pan wcześniej zadał, wskaźniki do zmiennych są dla mnie jasne (co pośrednio potwierdziłem odpowiedzią) Tutaj chciałem pokazać wskaźniki do funkcji, a raczej sposób w jaki postrzegam ich wykorzystanie/użycie.

    Jeśli chodzi o tą poprawioną przez Pana część mojego kodu, to przed chwilą sprawdziłem i moja wersja kodu działa. Proszę o wskazanie miejsca w którym popełniłem błąd i wyjaśnienie mi tego.

    Pozdrawiam i dziękuję za poświęcony czas!
  • #17 7785721
    Freddie Chopin
    Specjalista - Mikrokontrolery
    michalko12 napisał:
    Do zmiany wywołanie funkcji:


    Jedna i druga wersja jest poprawna - niczego nie trzeba zmieniać. Druga wersja za to jest czytelniejsza, bo od razu wiadomo, że to nie jest zwyczajna funkcja tylko wskaźnik.

    4\/3!!
  • #18 7785967
    davidpi
    Poziom 10  
    Witam.
    Wskaźniki to naprawdę ciekawe stworzenia, ale z własnego doświadczenia wiem, że początkującemu programiście zawsze sprawiają problemy. Jednak ich zrozumienie i opanowanie daje dużo satysfakcji i bardzo ułatwia życie. Dlatego myśle, że żadne krótkie rady i na szybko pisane programy nie sprawią, że ktoś zrozumie dokłądnie o co tu chodzi.
    Czy się chce czy się nie chce trzeba sięgnąć do fachowej literatury.
    I tutaj chcę polecić dwie pozycje, które pewnie i tak wszyscy znają :). Pierwsza z nich to "Symfonia C++" autorstwa Pana Grębosza. Natomiast druga to megatotoriał "Od zera do gier kodera" autorstwa XION'a. Zwłąszca ta druga pozycja jest godna uwagi i każdy początkujący programista c/c++ powinien ją znać.
    Jest tam wręcz łopatologicznie omówione zagadnienie wskaźników i nie tylko. Po przeczytaniu rozdziału nie da sie tego nie zrozumiec. Dlatego polecam
  • #19 7786012
    tmf
    VIP Zasłużony dla elektroda
    Skoro nie widzisz potrzeby stosowania wskaznikow to ich po prostu nie stosuj. Jak sie potrzeba pojawi to zrozumiesz po co sa :) Jeden z przykladow: masz funkcje, ktora sortuje lancuchy. Ale np. raz chcesz posortowac od najmniejszego do najwiekszego, innym razem odwrotnie, jeszcze innym uwzgledniajac strone kodowa. Zamiast pisac 3 oddzielne funkcje sortujace, piszesz jedna, a samo porownanie znakow w lancuchu piszesz jako oddzielna funkcje. Teraz do funkcji sortujacej przekazujesz jako parametr wskaznik do funkcji porownujacej znaki i masz to co chciales, prosto i elegancko. Innym przykladem jest realizacja tzw. callbackow. Np. chcesz zeby asynchronicznie za np. sekunde wywolac jakas funkcje. Mozesz uzyc timera i przerwania, ale jesli takich wywolan asynchronicznych masz wiecej to prosciej w timerze zrobic uniwersalna obsluge z kolejka takich wywolan. Dodajesz do kolejki wskaznik na wywolywana funkcje i sprawa elegancko zalatwiona. Przyklady mozna mnozyc, google pomoga.
  • #20 7786190
    MinisterQ
    Poziom 18  
    kazeciak napisał:
    Dziękuję za odpowiedzi, nie wszystko jest jeszcze dla mnie jasne, ale chyba zaczynam rozumieć zagadnienie. Proszę rzucić okiem na ten przykład i na jego podstawie określić czy "załapałem" czy może jednak nie do końca:

    
    --------------------------------
    get_data(int a , void(*wskaznik)(void))
        {
        (...);
        wskaznik();
        }
    
    void send_msg(void)
        {
        (...);
        }
    ---------------------------------
    
    get_data(sens_1 , send_msg) ;
    
    ---------------------------------
     



    Wydaje mi się, że taka operacja jest możliwa, zastanawiam się tylko nad korzyściami jakie z niej płyną, coś gdzieś dzwoni, ale jeszcze nie wiem który to kościół...


    EDIT:
    Oczywiście w tym przypadku wg mojego założenia miał to być wskaźnik na funkcję.


    Generalnie zasadę podłapałeś. Ale w przypadku takich konstrukcji jak wywoływanie funkcji za pomocą wskaźników jest jeden poważny problem: przekazywanie parametrów do tych funkcji. Akurat w Twoim przypadku, gdy argumentów do funkcji nie ma (void) to nie ma tego problemu, ale gdyby były - to byłby. ;)
    Różne kompilatory na różnych architekturach przekazują argumenty do funkcji w różny sposób - to zależy od tego jakie ustawienia ma kompilator (bądź ograniczenia), ile ma rejestrów procesor w maszynie, etc. Więc na początku swojej zabawy z programowaniem w C i wskaźnikami odradzam takich zabaw. ;)

    A co do samych wskaźników... Każda operacja na tablicy jest równocześnie operacją na wskaźnikach do pewnych obszarów pamięci, np:

    
    
    	char tablica[4];        //deklaracja tablicy 4 bajtow na stosie
    	char *wskaznik;       //deklaracja wskaznika do bajtow
    	
    	wskaznik = tablica;   //przypisanie tablicy do wskaznika
    	
    	tablica[1] = 'a';             //wpisanie wartosci 'a' pod 1 index w tablicy
    	*(wskaznik + 1) = 'a';    //to samo co wyzej tyle ze w wersji wskaznikowej
    
    
  • #21 7786225
    tmf
    VIP Zasłużony dla elektroda
    MinisterQ - cos sciemniasz z tymi parametrami do funkcji przekazywanej jako wskaznik. W czym konkretnie miales problem? Podobnie ilosc rejestrow - piszac w C masz pewien poziom abstrakcji od sprzetu, zabawa z rejestrami moze posluzyc do napisania optymalniejszego kodu, ale nigdy nie jest to problemem. Kompilator powinien sie wszystkim zajac sam.
  • #22 7786430
    rpal
    Poziom 27  
    MinisterQ napisał:
    Ale w przypadku takich konstrukcji jak wywoływanie funkcji za pomocą wskaźników

    Panowie jak już coś piszecie to wyrażajcie się precyzyjnie a to wyżej to właśnie przykład jej braku. o co chodzi o wywołanie funkcji za pomocą wskaźników czy przekazanie do funkcji parametru w postaci wskaźnika. Nie jestem tu żadnym guru w sprawie C jednak kol. MinisterQ co nie co opowiada bzdury bo jesli kompilator jest do "C" to ma obsłużyć tak podstawową składnie jak trzeeba czyli prawidłową obsługę m.in. wskaźnika a jeśli tego nie robi prawidlowo to albo nie jest C albo są błedy w programie. I nie ma tu nad czym polemizować. Ale to już wcześniej napisano.
  • #23 7786512
    MinisterQ
    Poziom 18  
    tmf napisał:
    MinisterQ - cos sciemniasz z tymi parametrami do funkcji przekazywanej jako wskaznik. W czym konkretnie miales problem? Podobnie ilosc rejestrow - piszac w C masz pewien poziom abstrakcji od sprzetu, zabawa z rejestrami moze posluzyc do napisania optymalniejszego kodu, ale nigdy nie jest to problemem. Kompilator powinien sie wszystkim zajac sam.


    W sumie masz rację...
    Moja wypowiedź była skutkiem tego, iż przez dłuższy okres czasu, kiedyś tam, programowałem pod AmigaOS i jego klonami, i tyko tam musiałem czasem pisać procedury które były zdefiniowane jako wskaźnik, i były wołane z parametrami (np. hooki). Na żadnej innej platformie której dotykałem nie musiałem tego robić... ;)

    A problem wynikał z tego, iż oryginalnie klasyczny AmigaOS powstał na procesory serii Motorola 680xx, i argumenty do funkcji (systemowych) przyjmował TYLKO poprzez rejestry procesora - D0-D7, oraz A0-A5 (A6 był wskaźnikiem na bazę biblioteki, a A7 to ramka stosu). Wraz z nadejściem następców systemu klasycznego kompilowanych na procesory PowerPC oraz x86, trzeba było to jakoś załatać... x86 ma relatywnie mniej rejestrów i funkcje przyjmują argumenty przez stos, a nie przez rejestry, na PowerPC część rejestrów idzie na emulację procesora m68k zaszytą w systemie, a reszty jest już za mało by zmapować wszystkie rejestry m68k dla "normalnego", nieemulowanego API. Suma summarum trzeba było stosować jakieś dzikie makra, które łatały kod tak, by mógł być rekompilowany na wszystkie platformy (klasyczną i następców) bez większych zmian, i z tego wynikały głównie problemy.

    A żeby nie przynudzać, to napisałem na szybko programik który wywołuje procedurę zdefiniowaną jako wskaźnik z parametrami, i oczywiście działa bez problemu:

    
    void send_msg(int a, int b) ; 
    
    
    void get_data(void(*wskaznik)(int a, int b))
    {
        wskaznik(1, 2);
    }
    
    void send_msg(int a, int b)
    {
    	printf("a:%ld b:%ld", a, b);
    }
    
    
    int main(int argc,char *argv[]){
    	get_data(send_msg);	
    }
    


    Niniejszym przepraszam za lekką dezinformację. ;)
  • #24 7786999
    rpal
    Poziom 27  
    a na koniec skompiluje ten kod i zobacz ile zajmie miejsca kiedy odwołujesz się do funkcji poprzez jes wskaźnik a potem porównaj kiedy wywołasz send_msg() z parametrami przekazanymi przez wartość. Bo wg. twój przykład do sztuka dla sztuki bez żadnego konkretnego uzasadnienia :)
  • Pomocny post
    #25 7787169
    MinisterQ
    Poziom 18  
    rpal napisał:
    a na koniec skompiluje ten kod i zobacz ile zajmie miejsca kiedy odwołujesz się do funkcji poprzez jes wskaźnik a potem porównaj kiedy wywołasz send_msg() z parametrami przekazanymi przez wartość. Bo wg. twój przykład do sztuka dla sztuki bez żadnego konkretnego uzasadnienia :)


    Oczywiście że tak, ale po pierwsze: nie ja ten przykład z wywoływaniem procedur zdefiniowanych jako wskaźnik w tym wątku wymyśliłem, po drugie - chodzi tylko o dodatkowy przykład tego jak działają wskaźniki.
  • #26 7787200
    tmf
    VIP Zasłużony dla elektroda
    MinisterQ: mysle, ze zaszlo pewne nieporozumienie. Funkcje systemowe w dawnych czasach po prostu oczekiwaly parametrow w konkretnych rejestrach. Poniekad do tej pory tak jest. Stad piszac w C trzeba bylo pisac tak, zeby przy wywolywaniu funkcji systemowych odpowiednie dane byly w stosownych rejestrach. To nie ma nic wspolnego z architektura procesora. Kompilatory C o ile to mozliwe ciagle przekazuja parametry za pomoca rejestrow - jest to efektywniejsze. Dopiero kiedy rejestrow nie starcza stosowane sa inne metody - np. przekazywanie parametrow przez stos. Problemu nie ma kiedy biblioteka systemowa i wygenerowany kod korzystaja z tego samego kompilatora (o tym samym ABI), szopki sie zaczynaja kiedy zmienia sie ABI, no ale to juz inna bajka.
  • #27 7787228
    MinisterQ
    Poziom 18  
    tmf napisał:
    MinisterQ: mysle, ze zaszlo pewne nieporozumienie. Funkcje systemowe w dawnych czasach po prostu oczekiwaly parametrow w konkretnych rejestrach. Poniekad do tej pory tak jest. Stad piszac w C trzeba bylo pisac tak, zeby przy wywolywaniu funkcji systemowych odpowiednie dane byly w stosownych rejestrach. To nie ma nic wspolnego z architektura procesora. Kompilatory C o ile to mozliwe ciagle przekazuja parametry za pomoca rejestrow - jest to efektywniejsze. Dopiero kiedy rejestrow nie starcza stosowane sa inne metody - np. przekazywanie parametrow przez stos. Problemu nie ma kiedy biblioteka systemowa i wygenerowany kod korzystaja z tego samego kompilatora (o tym samym ABI), szopki sie zaczynaja kiedy zmienia sie ABI, no ale to juz inna bajka.


    W tym konkretnym przypadku miało (niestety) dość dużo wspólnego z architekturą procesora, w tym przypadku MC680xx - AmigaOSy były pisane tak, by najlepiej (najwydajniej) wykorzystać tą architekturę. To spowodowało w tym konkretnym przypadku dużo problemów przy ich przepisywaniu na inne architektury (np. przywiązanie do big-endian, czy kwestie przekazywania parametrów przez rejestry + przenośność starych źródeł czy gotowych programów o których pisałem wcześniej). Ale to offtop, i nie ma sensu tego ciągnąć dalej.
  • #28 7789477
    nenpa8lo
    Poziom 17  
    kazeciak napisał:
    jaką odgrywają wskaźniki, nie potrafię ich używać, nie wiem do czego one służą, czemu z nich korzystać itd.
    To ja może nie technicznie, pamiętam jak dziś jak na uniwerku pani od programowania mi powiedziała no jak sobie chcesz, ale w C bez wskaźników niewiele da się zrobić i dziś rozumiem że miała świętą rację :D
  • #29 7799790
    kazeciak
    Poziom 15  
    Panowie!

    Bardzo dziękuję za odpowiedzi! Przepraszam też, że nie odzywałem się tyle czasu (nagły przypadek w pracy)
    Obiecuję, że dzisiaj odniosę się do wszystkich odpowiedzi, tylko niech dojdę do siebie w końcu.

    Pozdrawiam,
    Marcin
  • #30 7808692
    kazeciak
    Poziom 15  
    Witam

    Wskaźniki jako takie zainteresowały mnie, gdyż występują w 3/4 kodów źródłowych jakie przeglądam w poszukiwaniu jakiś rozwiązań. Tak było i w tym przypadku, zastanawiałem się jak zrobić rozbudowane, wielopoziomowe menu obsługiwane czterema przyciskami (LCD 2x16) ale w sposób poprawny, tzn nie na skróty, aby "jakoś tam" zadziałało w tym konkretnym projekcie, tylko abym mógł je swobodnie wykorzystywać w przyszłości.
    Oczywiście google potrafię używać, ale nie znalazłem niczego, co by było za razem eleganckie i nie zajmowało astronomicznych ilości pamięci. Sam też nie bardzo potrafię coś wymyślić.
    Powracając do samych wskaźników, to te parę dni które upłynęło od momentu gdy o nie zapytałem, spowodowały że trochę się już z nimi oswoiłem, jednak muszę ich użyć jeszcze parę razy świadomie i w praktyce.

    Jeszcze raz dziękuję za poświęcony czas!

    Pozdrawiam,
    Marcin
REKLAMA