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

Jak działa wskaźnik na wskaźnik w C na AVR? Czy można użyć jednego wskaźnika?

squelch 30 Lip 2017 14:11 2514 18
  • #1 16616387
    squelch
    Poziom 11  
    Witam
    wie ktoś może jak działa wskaznik na wskaznik? Bo na AVR jest to często używane. Bo jak mam taką funkcję np.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    No to wiadomo te ** to jest wskaźnik na wskaźnik ale czy nie można byłoby zrobić tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    zrobimy coś takiego że przekazujemy adres zmiennej np &a, i teraz jak chcę znać adres od której zaczyna się alokacja to piszę *a. Tylko trzeba by było zamiast char napisać pewnie int(bo adres będzie 16bit). Można tak?

    Ale kurczę no jakoś nie jestem wstanie tego wskaznika na wskaznik wyobrazić.
  • Pomocny post
    #2 16616425
    BlueDraco
    Specjalista - Mikrokontrolery
    W tym drugim przypadku procedura dostaje jako argument wartość adresu. *ret - to bajt wskazywany przez ten adres. Temu bajtowi (znakowi) próbujesz nadać wartość równą adresowi - nie zmieśżci się i nie ma to żadnego sensu.

    W pierwszym przypadku dostajesz jako argument adres, pod którym zapisany jest adres, i pod ten adres zapisujesz swój adres - to ma jakiś sens.

    Moim prywatnym zdaniem jednak używanie dynamicznej alokacji pamięci w uC, który tej pamięci ma pojedyncze KiB, jest pozbawione jakiegokolwiek sensu i jest proszeniem się o błędy.
  • Pomocny post
    #3 16616428
    Konto nie istnieje
    Konto nie istnieje  
  • Pomocny post
    #5 16616846
    tmf
    VIP Zasłużony dla elektroda
    Tak, dobrze to pokazałeś. Najłatwiej sobie rozkminiać takie problemy w symulatorze. Masz na wszystko podgląd.

    Dodano po 3 [minuty]:

    BlueDraco napisał:

    Moim prywatnym zdaniem jednak używanie dynamicznej alokacji pamięci w uC, który tej pamięci ma pojedyncze KiB, jest pozbawione jakiegokolwiek sensu i jest proszeniem się o błędy.


    A jakie znaczenie ma ilość dostępnej pamięci? Jeśli masz 1 MB, a będziesz alokował bloki po kilkaset kB, to uważasz, że sens to będzie miało?
    Owszem, używając alokacji dynamicznej trzeba uważać, z pewnością nie należy jej nadużywać. Niemniej pisząc, że alokacja dynamiczna na MCU mającym parę kB RAM jest pozbawiona sensu, w praktyce piszesz, że używanie C++ w takich warunkach jest pozbawione sensu, podobnie jak wielu technik programowania - np. dynamicznych list. Z tym trudno się zgodzić.
  • #6 16841255
    squelch
    Poziom 11  
    Cześć

    Czasami po pewnym czasie wracam do niektórych zagadnień stąd ta przerwa.

    Równie dobrze można byłoby napisać z jedną gwiazdką i do takiego argumentu możemy przekazać adres wskaźnika. Potem pod ten adres wyłuskany czyli adres wskaznika wpisujemy adres zalokowanej pamięci. Wydaje mi się że można by tak było.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #7 16841265
    BlueDraco
    Specjalista - Mikrokontrolery
    *ret jest typu char - ten błąd został już wytłumaczony wyżej. Do 8-bitowej zmiennej typu char próbujesz zapisać wskaźnik p, kt
    ry ma więcej niż 8 bitów. Cały pomysł jest mało sensowny (przyczyny też wytłumaczone), ale jeśli już, to argument powinien być typu char **ret.
  • #8 16841290
    Konto nie istnieje
    Konto nie istnieje  
  • #9 16843472
    squelch
    Poziom 11  
    Cytat:

    Do 8-bitowej zmiennej typu char próbujesz zapisać wskaźnik p,

    nie do końca jak bym przekazał do funkcji adres wskaźnika
    char *wsk;
    i przekazany argument &wsk;
    tzn. że po wyłuskaniu ten adres(zalokowanej pamięci) zapisuję do wskaźnika a nie do zmiennej typu char wskaźniki są 16 bitowe. Przecież taki wskaźnik on chce tylko adres co mi szkodzi przekazać adres innego wskaźnika
  • #10 16843486
    Konto nie istnieje
    Konto nie istnieje  
  • #11 16843547
    squelch
    Poziom 11  
    No wiadomo że ret jest lokalny ja przekazuje np. adres wskaźnika tj. powiedzmy 0x03 funkcja wyłuskuje mi to co pod tym adresem jest to jest sam wskaźnik i tam zapisuje adres więc zmienni mi globalny wskaźnik tj. zapisze do niego adres zalokowanej pamięci ale czytając twój post to nie bardzo wiem o co ci chodzi ret=costam przecież w kodzie jasno jest pokazane *ret.

    No bo słuchajcie patrząc tak z logicznego punktu widzenia to według mnie w ogóle nie powinno definiować się wskaźników na wskaźnik tak.
    char **wsk;
    przecież mogę zdefiniować sobie wskaźnik tak
    char *wsk i do niego przekazywać adres innego wskaźnika np. przykład który mi podałeś.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    nie widzę różnicy w takim zapisie
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Po prostu do wskaźnika wrzucam adres innego wskaźnika. Według mnie ale mówię to jest moje zdanie i nie chcę tutaj się wymądrzać ani poprawiać twórców C używanie ** ma sens jak chcę się dostać do tego na co wskazuje ten drugi wskaźnik (Bo pierwszy wskazuje na drugi wskaźnik a ten drugi na zmienną w przypadku który był poniżej).

    Np. jakbym chciał stworzyć łańcuszek tj. wskaźnik na wskaźnik na ... to
    char *wsk1;
    char *wsk2;
    char *wsk3;
    char *a;

    wsk1=&wsk2;
    wsk2=&wsk3
    wsk3=&a;

    1-adres 2 wsk
    2-adres 3 wsk
    3-adres zmiennej a
    jakbym chciał wyłuskać a to napisałbym tak ***wsk1. No to to ma sens (tak mi się wydaje) a idąc tokiem Piotrus_999 to musiałbym pisać ***wsk1; żeby zdefiniować wskaźnik a w moim przypadku to jest tylko 1 gwiazdka można tak?
  • Pomocny post
    #12 16843561
    Konto nie istnieje
    Konto nie istnieje  
  • Pomocny post
    #13 16843570
    Freddie Chopin
    Specjalista - Mikrokontrolery
    squelch napisał:
    nie widzę różnicy w takim zapisie

    Na szczęście kompilator widzi.

    Zrozum że ta dyskusja jest bezcelowa jeśli my piszemy o języku C, a Ty o "mój prywatny i fajniejszy wariant C który sobie właśnie wymyśliłem".

    squelch napisał:
    Według mnie ale mówię to jest moje zdanie i nie chcę tutaj się wymądrzać ani poprawiać twórców C używanie ** ma sens jak chcę się dostać do tego na co wskazuje ten drugi wskaźnik (Bo pierwszy wskazuje na drugi wskaźnik a ten drugi na zmienną w przypadku który był poniżej).

    A masz jakąś motywację tych wszystkich dziwnych pomysłów, czy po prostu na klawiaturze zepsuł Ci się symbol '*' że tak kombinujesz?

    squelch napisał:
    No to to ma sens (tak mi się wydaje)

    Zgadza się - wydaje Ci się. C i C++ (przy czym C++ bardziej) są jezykami "strongly typed" na etapie kompilacji, a to co sugerujesz oznaczałoby, że kompilator już by nie wiedział czy chodzi Ci o "char" (1 bajt), czy może o "char *" (więcej niż 1 bajt).

    squelch napisał:
    można tak?

    Nie można.
  • #14 16843695
    squelch
    Poziom 11  
    Cytat:

    A masz jakąś motywację tych wszystkich dziwnych pomysłów, czy po prostu na klawiaturze zepsuł Ci się symbol '*' że tak kombinujesz?

    Po prostu nie przyjmuje niektórych rzeczy jak inni jako pewnik tylko szukam dopytuję czy można inaczej dlaczego tak się dzieje itp.

    Ale ok dzięki za odpowiedzi wasze w tym temacie.
  • Pomocny post
    #15 16843716
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Nie można tak zrobić, bo nie zgadzają się typy.

    Do "char" można przypisać "znak", a odczytać "znak".
    Do "char *" można przypisać "adres zmiennej w której jest znak", a nie "adres w którym jest coś". Odczytać można ten adres, lub - przez pojedynczą dereferencję - znak który jest pod tym adresem.
    Do "char **" można przypisać "adres zmiennej w której jest adres zmiennej w której jest znak". Odczytujesz "adres zmiennej w której jest adres zmiennej w której jest znak", po pojedynczej dereferencji - "adres zmiennej w której jest znak", lub po podwójnej dereferencji "znak".
    itd.

    Z tego względu jak do zmiennej "x" typu "char *" przypiszesz "adres zmiennej w której jest adres zmiennej w której jest znak" to akurat kompilator tylko ostrzeże Cię, że robisz coś bardzo głupiego, niemniej jednak próba odczytania "**x" skończy się błędem kompilacji. Związane jest to z tym, że wyrażenie to kompilator rozpatruje jako "*(*x)" (jeśli i to kwestionujesz, to szukasz informacji o tym jaka jest łączność operatorów i ich priorytet). To co jest wewnątrz nawiasów zwróci "znak", np. literkę 'A', typu "char". To co jest poza nawiasem jest błędem kompilacji, ponieważ nie jest możliwa "dereferencja znaku" - operacja "*'A'" nie ma żadnego sensu.

    Tylko i wyłącznie tyle. Nie musisz tego przyjmować na wiarę ani uważać że "tak jest bo pewnie ludzie na forum sobie tak założyli". Taki jest standard tego języka i koniec - jeśli nie wierzysz, to po prostu spróbuj skompilować swój kod i przekonasz się, że kompilator też ma inne zdanie niż Ty. O ile w przypadku przypisania adresów kompilator obdzieli Cię tylko warningiem (kompilator C++ zgłosiłby błąd - jedna z głównych zalet tego języka), o tyle próby odczytu które proponowałeś są niemożliwe do wykonania bez rzutowania, ponieważ w każdym innym przypadku spowodują błąd.

    https://ideone.com/JtOr0M

    Dokładnie tak samo jest w przypadku innych typów - np. w zmiennej typu float nie można przechowywać wskaźnika, a w zmiennej typu int nie można przechowywać liczby z ułamkiem. To że akurat operacja z drugiego przykładu nie powodują błędów jest związane z tym, że w standardzie języka zdefiniowane są pewne "konwersje domyślne" (szukasz pod hasłem "implicit conversions"), które w takiej sytuacji, we w pełni zdefiniowany sposób, skonwertują liczbę z ułamkiem na liczbę całkowitą (obcinając część ułamkową). Takie domyślne konwersje nie istnieją między typem "wskaźnik" a "wskaźnik na wskaźnik", a więc są albo "undefined behaviour", albo powodują błąd kompilacji.

    Możesz się z tym nie zgadzać lub nie, niemniej jednak próby kłócenia się i przekonywania nas są bezcelowe. Jeśli te cechy języka C czy C++ Ci nie odpowiadają, to zacznij używać Pythona lub jakiegoś innego języka w którym określenie typu zmiennej nie jest potrzebne.
  • Pomocny post
    #16 16844258
    JacekCz
    Poziom 42  
    tmf napisał:
    ... w praktyce piszesz, że używanie C++ w takich warunkach jest pozbawione sensu, podobnie jak wielu technik programowania - np. dynamicznych list. Z tym trudno się zgodzić.


    W pełni C++ ma sens, choć bez / z ostrożnością co do biblioteki standardowej.

    A jakbym nie miał spać, myśląc czy użyłem właściwej ilości gwiazdek (żart) albo czy inkrementuję to, co zamierzałem (dla mnie poważnie), to moim sposobem jest referencja na wskaźnik. Jest to w obrębie C++, ale ani nikogo chyba nie rzuca na kolana.

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


    PS. OK, to takie C z klasami, nie będę się kłócił.

    PPS: kol @squelch , twoje gdybania zamiast poczytania są błędne.
  • #18 16851228
    Konto nie istnieje
    Konto nie istnieje  
REKLAMA