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

[AVR][C] jak działać ze stringami lub wskaźnikami

mirekk36 05 Cze 2008 19:14 12496 35
  • #1 5216791
    mirekk36
    Poziom 42  
    Witam,

    sorki za może dziwne pytanie ale dopiero uczę się C, to początki. Otóż jak tu działać na tzw STRINGACH

    chciałbym np w programie do jakiejś zmiennej czy wskaźnika (obojętnie co) w trakcie programu w różnych np IF'ach podstawiać jakiś tam różny tekst. No i tu napotykam na ogromny problem. Jak to robić.

    Narazie wiem tyle, że jak zdeklaruję sobie np:

    char my_str[] = "jakis napis";


    to wszystko będzie dobrze i będę mógł sobie używać my_str jako mój string do wyświetlania np napisów na LCD

    ale już przecież w kodzie nie można sobie napisać :

    my_str = "jakis napis";


    --------------------------

    próbowałem więc tak:

    char *wsk_str;


    a potem w kodzie zrobiłem sobie:

    wsk_str = "jakis napis" 


    i jeśli tylko taka jedna linijka jest to jakoś to działa ale jeśli dalej gdzieś
    zrobię

    wsk_str = "inny tekst" 


    to już jakieś cyrki mi się dzieją, eeeeh coś nie mogę zaskoczyć z tym

    .......................................

    generalnie - jak działać na stringach - albo jak sobie z tym radzić, żeby było jakoś podobnie jak w Bascomie czy jak na PCtach w Pascalu. Tam string to string i wiadomo co i jak - a tu???? .... taaak wiem, na pewno jest lepiej tylko trzeba z tym zaskoczyć - proszę o jakieś podpowiedzi naprowadzające

    pozdrawiam
  • Pomocny post
    #2 5217133
    Freddie Chopin
    Specjalista - Mikrokontrolery
    string jest tablicą charów.

    deklarujac
    char string[]="abcd";
    otrzymujesz tablice 5cio elementowa, do ktorej zmienna string jest wskaznikiem [;
    1. dlaczego 5 elementowa? bo masz w niej 'abcd\0' - znak \0 (ASCII 0) oznacza koniec stringa
    2. dlaczgo wskaznik? otoz zmienna 'string' jest wskaznikiem pierwszego elementu tablicy czyli string[0].

    w istocie w C nie da sie przypisac do zmiennej stringa w sposob bezposredni, jednak jest to do zalatwienia jedna uniwersalna funkcja, ktora w kazdym kompilatorze juz jest i jest nia chyba strcpy. jak ci sie nudzi i chcesz sie czegos nauczyc, to mozesz napisac sobie taka sam <;

    idea jest po prostu taka, ze zamiast:
    zmienna="string";
    robisz
    funkcja(zmienna,"string");

    generalnie w jezyku C nie ma czegos takiego jak string i wszystko opiera sie na tablicy. dlatego trzeba traktowac stringi jako taka wlasnie tablice. tak samo przeciez nie machniesz w jednej linijce czegos takiego:

    array={1,2,3,4,5}; (oczywiscie poza deklaracja na poczatku kodu)

    ale juz mozesz zrobic tak:

    *string='a';
    *(string+1)='b';
    *(string+2)='c';

    albo

    string[0]='a';
    string[1]='b';
    string[2]='c';

    BARDZO WAZNA RZECZA jest to, abys stringa zakonczyl znakiem NULL - \0 co pozwoli ci przetwarzac w funkcjach stringi niezaleznie od ich dlugosci.

    dlatego rozmiar jakiejs zmiennej, ktora uzyjesz do przechowywania stringow musi byc o 1 wiekszy:

    char zmienna[10];

    pomiesci ci to napis o dlugosci 9 znakow, 10 znakiem _powinno_ byc \0. jak go nie dasz, to oczywiscie sie nic nie stanie, ale przetwarzanie stringow bedzie trudniejsze, a program moze isc czasem w maliny. zwykle funkcje przetwarzaja stringa pod postacia:

    while(*(++string_ptr))
    {
    ...
    }

    tak wiec robi ona cos do momentu napotkania zera. jak zera nie bedzie, to ci przemieli caly RAM i w ktoryms tam momencie sie wylozy <:

    mam nadzieje ze znasz angielski [; http://www.cplusplus.com/reference/clibrary/cstring/strcpy.html
    jak nie to po polskiemu: http://pl.wikibooks.org/wiki/C/strcpy

    jak poszukasz po necie, to znajdziesz gdzies pewnei zrodlo tej funkcji, pewnie zajmuje ze 3 linijki

    0x41 0x56 0x45!!
  • Pomocny post
    #3 5217821
    szelus
    Poziom 34  
    mirekk36 napisał:

    próbowałem więc tak:

    char *wsk_str;


    a potem w kodzie zrobiłem sobie:

    wsk_str = "jakis napis" 


    i jeśli tylko taka jedna linijka jest to jakoś to działa ale jeśli dalej gdzieś
    zrobię

    wsk_str = "inny tekst" 


    to już jakieś cyrki mi się dzieją, eeeeh coś nie mogę zaskoczyć z tym


    Generalnie dobrze kombinujesz ;), tak jak najbardziej można w C, ale...
    W AVR, z uwagi na rozdzieloną pamięć programu i danych, przy zwykłych napisach i wskaźnikach do nich, te napisy muszą się znaleźć w RAMie, bo do FLASHa kompilator nie potrafi się wprost odwołać (GCC, niestety, nie jest przystosowane do architektury typu harwardzkiego). Zatem na początku kompilator kopiuje napisy do RAMu, a ponieważ tego jest mało, to mogą zostać np. zamazane przez stos. Więc upewnij się, że tak nie jest u Ciebie.
    Można wymusić umieszczenie napisów wyłącznie we FLASHu, ale wtedy trzeba sie do nich odwoływać w specjalny sposób. Poczytaj w manual-u do AVR Libc o przechowywaniu stringów w pamięci programu http://www.nongnu.org/avr-libc/user-manual/pgmspace.html
  • #4 5217931
    mirekk36
    Poziom 42  
    dziękuję panowie bardzo za takie właśnie krótkie kompendium wiedzy. Czegoś takiego oczekiwałem. Trochę mnie przeraża może jeszcze to całkiem nowe jak dla mnie podejście do stringów i ich obróbki, ale w końcu cała winda chodzi w C ;) (linuxy chyba też?) - więc nie będę marudził tylko się uczył. Freddie fajny opis, szelus dobre uzupełnienie i źródła

    THX
  • #5 5218726
    Bigfoot
    Poziom 25  
    Nie wiem jak w AVR ale w moim kompilatorze dla PIC by wyswietlac napis statyczny (z ROMU) wystarczy przed stringiem dodac const by poinformowac, ze pobranie znakow dokona sie z pamieci programu. Bez tego "dodatku" kompilator wyswietli tylko napisy z pamieci danych (pamieciozerne, ale tez czasem potrzebne, jesli tworzymy napis dynamicznie). Funkcja do wyswietlania napisow stringa typu NULL-end terminated ponizej (ta akurat dla UART-a ale w jasny sposob pokazuje idee wysylania znak po znaku, ktora moze sie koledze przydac)

    BF

    
    void SendString(const char* Text){
    while(*Text){           //krec tak dlugo az nie napotkasz konca stringa (NULL)
    	while(!TRMT);        //czekaj na zezwolenie (flaga sprzetowa UART)
       TXREG = *Text++;     //wyslij kolejny znak stringa Text
    	}
    }
    


    BF
  • #6 5218761
    fantom
    Poziom 31  
    Bigfoot napisał:
    Nie wiem jak w AVR ale w moim kompilatorze dla PIC by wyswietlac napis statyczny (z ROMU) wystarczy przed stringiem dodac const by poinformowac, ze pobranie znakow dokona sie z pamieci programu.


    W AVR-GCC tak nie jest.
  • #8 5219356
    mirekk36
    Poziom 42  
    odnośnie zapamiętywania i pobierania stringów z pamięci ROM(flash) to nie mam jakby problemów ale chodzi mi o sposoby obróbki tych "ala" stringów. Tzn po wykładzie kolegi Freedie już czuję o co chodzi ale np tak:

    w pascalu(delphi) mam taką swoją ulubioną i często potrzebną mi funkcję

    function ScanStrSP(var Text: string; Separator: string): string;
    var
      I: Integer;
    begin
      Text:=TrimLeft(Text);
      I := 1;
      while (I <= Length(Text)) and (Text[I] <> Separator) do Inc(I);
      Result := Copy(Text, 1, I-1);
      Text := Copy(Text, I+1, Length(Text)-I);
    end;


    nie miałem najmniejszego problemu z przerobieniem jej na Bascoma - i zrobiłem to tak:

    Function Scanstrsp(text As String , Byval Sep As String) As String
    Local I As Byte , Dl As Byte
    
      I = 1
      While I <= Len(text)
        If Mid(text , I , 1) <> Sep Then
          Incr I
        Else
          Exit While
        End If
      Wend
      Dl = Len(text) - I
      Decr I
      Scanstrsp = Left(text , I)
      Text = Right(text , Dl)
    
    End Function


    tylko, że w Pascalu i Bascomie jest podobne podejście do stringów. A w C jak widzę - będę musiał zrobić potrójne salto z podwinięciem i czterema fikołkami, żeby tak obrobić string'a ;) (na moim dotychczasowym poziomie wiedzy oczywiście)

    znalazłem wprawdzie w C tę standardową bibliotekę, która oferuje podstawowe operacje na takich łańcuchach znaków jak sklejanie, wyszukiwanie itp - ale muszę to podejrzeć i zobaczyć , nauczyć , przestawić myślenie - tak jak to się robi na co dzień w C ;)
  • #9 5219413
    Freddie Chopin
    Specjalista - Mikrokontrolery
    jesli dobrze widze, to funkcja ta dzieli stringa na dwa kawalki, oddzielone separatorem.

    jesli tak, to da sie to zrobic w C bardzo prosto. jesli nie, to nie czytac dalej [;

    na poczatku programu trzeba miec zadeklarowane dwa bufory:

    
    char bufor1[]="Przykladowy tekst, ktory podzielimy", bufor2[30];
    


    teraz funkcja powinna wygladac MNIEJ WIECEJ tak:
    petla typu do...while (zalatwi to od razu sprawe zakonczenia jednego ze stringow), ktora przepisuje najpierw jednego stringa do drugiego, sprawdzajac czy aktualny znak nie jest separatorem, a jesli tak, to zaczyna ona przepisywac stringa pierwszego od jakiegos miejsca na jego poczatek (przesuwac go)

    da sie to, jak wiadomo, zrobic na milion sposobow [; taki narzucajacy sie i w miare przejrzysty (do tego bardzo wazna lekcja - przekazywanie parametrow przez adres [; konieczne do operacji na tablicach lub wielu zmiennych w funkcjach):

    
    void ScanStrSP(*bufor1,*bufor2,*separator)
    {
        char *src,*dest;
    
        dest=bufor2; // na poczatku przepisujemy z bufor1 do bufor2 
        src=bufor1;
    
        do
        {
            if(*src==*separator) // jesli osiagniety zostanie separator, to pomijany jest aktualny krok, konczony jest string wynikowy i zmieniany wskaznik bufora docelowego
            {
                *dest='\0';
                dest=bufor1;
                continue;
            }
            *src++=*dest++; // rzeczywiste skopiowanie jednego znaku ze zrodla do bufora
        } while(*src) // petla trwa do osiagniecia znaku \0 w buforze zrodlowym, czyli przemielenia calego stringa
    
    }
    


    wywolanie takiej funkcji wygladac bedzie

    
    ScanStrSP(bufor1,bufor2,",");
    


    lub

    
    ScanStrSP(&bufor1[0],&bufor2[0],",");
    


    w efekcie po przemieleniu zawartosc buforow powinna wygladac nastepujaco:
    bufor1:
    " ktory podzielimy\0 ktory podzielimy\0"
    bufor2:
    "Przykladowy tekst\0<smieci do konca bufora>"

    oczywiscie mog sie mylic [; funkcja wycina separator - jesli ma go nie wycinac, to trzeba ja troche zmienic oczywiscie. jak wiec widzisz - cala sprawa zalatwiona jest jedna petla z jednym warunkiem koncowym i z jednym ifem w srodku [;

    0x41 0x56 0x45!!
  • #10 5219704
    ktrot
    Poziom 20  
    Jeżeli można wyciąć separator to trochę szybciej:
    
    char t1[]="jakis tekst";
    char * t2;
    
    i=0;
    while(t1[i++]!=' '); //separatorem jest tutaj spacja
    t1[i-1]=0;
    t2=t1+i;
    

    t1 zawiera napis "jakis" a t2 "tekst"
    oczywiście można dodać dodatkowe warunki gdyby separator nie istniał w ciągu oraz czy t1 da się podzielić (nie jest np jednoznakowy)
  • #11 5219738
    Freddie Chopin
    Specjalista - Mikrokontrolery
    tyle ze t2 w sumie niczego nie zawiera, bo operuje na zmiennej t1. w zalenosci od zastosowan moze to byc dobre lub zle.

    w sumie to petle mozna rozwiazac rowniez tym sposobem (najpierw znalezc separator, a potem przekopiowac reszte stringa, zastepujac separator znakiem \0.

    jak widac - ilu ludzi, tyle pomyslow [;

    0x41 0x56 0x45!!
  • #12 5219817
    ktrot
    Poziom 20  
    Cytat:
    tyle ze t2 w sumie niczego nie zawiera

    to prawda, źle się wyraziłem. W C ani t1 ani t2 nie zawiera żadnych
    napisów. Przed wykonaniem tych 3 linijek t1 wskazuje na napis "jakis tekst" a po wykonaniu t1 wskazuje "jakis" a t2 wskazuje na napis "tekst"
    To czy potrzebne jest kopiowanie zależy od tego co bedziemy robić z dalej z t1, czy np nie bedzie potrzebny jako bufor w pierwotnej wielkości.
  • #13 5220143
    mirekk36
    Poziom 42  
    dzięki za podpowiedzi, dzisiaj wieczorkiem będę miał co robić eeeeh - zaćwiczę to na śmierć, tym bardziej, że te wasze przykłady tak jednak, krótko daje się napisać. Więc tylko początkującemu jak mi, może się wydawać, że trzeba jakieś extra salta programistyczne dokonywać ;)

    .... ale ok zanim się wgryzę w kod wieczorkiem to od razu na gorąco jeszcze jedno dopytam odnośnie tch przykładów

    .... otóż chciałbym aby ta funkcja zwróciła mi jako parametr na wyjściu ten odcięty do separatora łańcuch natomiast skróciła łańuch wejściowy(czyli ten który podajemy do funkcji na starcie jako paramter)

    czyli tak na szybko kombinuję, żeby nie było tego void na początku tylko jakiś wskaźnik do tego odciętego łańcucha.

    hmmmm tylko co? wewnątrz funkcji trzeba by było jakoś (sorry za wyrażenie) - zaalokować pamięć RAM żeby to mogło odbywać się jakoś dynamicznie. Mówiąc o alokowaniu pamięci myślę jakbym robił to na PC'cie a może tu się w ogóle tak nie robi???

    albo może w ogóle w C nie stosuje się w ten sposób zwracania parametrów na wyjściu ?

    generalnie często stosuję tę funkcję gdy np przez RS232 przesyłam jakieś informacje, wiele parametrów. Pakuję je wtedy do długiego stringa i go całego wysyłam przez RS232 , np:

    "header;dana01;12;tekst;cokolwiek"


    a następnie tam gdzie zostaje odebrany ten cały string tą właśnie funkcją po kolei odzyskuję parametry (ja wiem w jakiej one są kolejności i które są liczbami a które tekstem itp)

    czyli pierwsze wywołanie funkcji np:

    hdr = ScanStrSP(moj_string, ';')


    spowoduje że w zmiennej hdr będę miał łańcuszek "header"

    a potem kolejno jakieś tam zmienne zdeklarowane i:

    dn01 = ScanStrSP(moj_string, ';')
    licz1 = ScanStrSP(moj_string, ';')
    txt  = ScanStrSP(moj_string, ';')


    i po tych operacjach wiadomo co mam w kolejnych zmiennych a w stringu przekazywanym moj_string pozostało już tylko słówko "cokolwiek" - bo był on za każdym razem skracany.

    oczywiście na razie nie proszę o gotowe rozwiązanie - bo wolałbym sam poćwiczyć wieczorkiem a później najwyżej dopytam - interesuje mnie tylko na teraz to co mówiłem wcześniej - czy da radę tak zwracać parametr na wyjściu z tej funkcji???? , a samo skracanie parametru wejściowego - to na pewno da radę bo można go jakoś przepisywać wewnątrz. Będę z tym kombinował
  • #14 5220210
    nsvinc
    Poziom 35  
    ludzie!! nie 'char' a UNSIGNED CHAR !! pierwsza istotna sprawa.

    Wskaznik na 'char' czy na 'unsigned char' to niewielka róźnica, bo bajt to bajt. Ale kompilator i tak zwróci ostrzerzenie przy kompilacji jesli pod adres wzkaznika na char zapiszemy zmienna typu unsigned char...

    ale: _W_TABLICACH_PRZECHOWUJĄCYCH_STRING_STOSUJEMY_UNSIGNED_CHAR_....
  • Pomocny post
    #15 5220215
    Freddie Chopin
    Specjalista - Mikrokontrolery
    bezposrednio nie jest to mozliwe tak jak ze zwroceniem wartosci liczbowej. funkcja w c moze zwrocic tylko JEDNA wartosc. moze zwrocic wskaznik - czyli jakby poczatek tego stringa. tyle ze zaalokowane wewnatrz funkcji zmienne po jej zakonczeniu sa zwalniane i nalezy zalozyc, ze przestaja istniec. oczywiscie wiadomo, ze przez chwile cos tam na tym stosie bedzie lezec, ale NIE ZAWSZE - rownie dobrze dane moga zostac zmasakrowane od razu po zamknieciu funkcji, dlatego nie mozna tak zakladac.

    rozwiazania sa 2.

    1. musisz miec globalny bufor, na ktorym bedzie operowala twoja funkcja (slabe rozwiazanie)
    2. musisz w funkcji nadrzednej miec lokalny bufor, ktorego adres podajesz do funkcji, tak zeby miala ona na czym operowac - dokladnie to jest zrobione w tym kodzie, ktory ja napisalem. zeby funkcja zwracala ci uchwycik do stringa przycietego od poczatku, wystarczy ze na koncu dopiszesz jedna linijke, ale skoro mowisz, ze ma nie byc gotowca, to ... to nie bedzie [;

    skracanie parametru wejsciowego (pozorne coprawda, bo RAMu tablica zajmuje wciaz dokladnie tylesamo, tyle ze zawartosc sie troche przesunela) rozwiazane jest rowniez w kodzie ktory ci tam wymodzilem powyzej <: sorry - na nastepny raz ostrzegaj od razu, ze ma nie byc gotowcow <:

    tak BTW to jakies ksiazki zwykle maja dosyc rozwiniete rozdzialy o tych kombinacjach jakimi jest praca ze stringami i przekazywanie 'z' i 'do' funkcji tablic. pogooglaj za opisem przekazywania parametru przez adres, tablicami i stringami w C... pierwszy wynik takiego wyszukiwania jest nawet sensowny

    to prace domowa masz, ale nie ma sie co zniechecac, bo C naprawde jest prosciutkie.

    0x41 0x56 0x45!!
  • Pomocny post
    #16 5220240
    ktrot
    Poziom 20  
    Przyjrzyj się dokładnie temu co napisałem - właśnie do separowania parametrów się doskonale nadaje. Skrócenie łańcuch następuje niejako samoczynnie - nie potrzeba dodatkowej pamięci kopiowania
    Ogólnie:
    zapis char t[]="abcde" oznacza tablicę 6 elementową (5 liter + 0) przy czym t z definicji wskazuje pierwszy znak (a) w związku z tym t+2 wskazuje 3 znak (c). Przypuśćmy, że 'c' jest separatorem wszysko czego potrzebujem do rozdzielenia tych 2 argumentów (ab i de) to zadeklarować pusty wskaźnik (który wskazuje cokolwiek) oraz wpisać 0 w miejsce c a temu nowemu wskaźnikowi przypisać wartość t+3 (czyli początek drugiego parametru - de).
    Możesz zadeklarować funkcję w sposób rekursywny tak aby wczytywała parametry niezależnie od ich ilości lub nieco prościej wywołać ją tyle razy ile jest parametrów za każdym razie podając na wejściu ten wskaźnik, który pozostał - (w moim przykładzie t2). Możemy też zamienić t1 i t2
    (jak przy innych zmiennych temp=t1; t1=t2; t2=temp) i wtedy wywołujemy wielekrotnie funkcję z tym samym parametrem t1.
    Można jeszcze prościej ale nię bedę teraz mieszał :)
    Zwróć tylko uwagę, że łatwo zadeklarować funkcję, które zwróci rozdzielone parametry w tablicy zadeklarowanej char *par[8] <- to jest tabela 8 parametrów (8 stringów).
  • #17 5220370
    nsvinc
    Poziom 35  
    ->mirekk36

    z tego co piszesz rozumiem ze chcesz parsować jakis konkretny string (długi string) wejsciowy i chlastać go na mniejsze wg odpowiednich zasad? Jesli tak to zbadaj ten kod

    
    rxr=0; _k=0;
    while (u1rxf[rxr]) //u1rxf w tym przypadku jest twoim 'długim' stringiem ktorego dzielisz na kaawałki, rxr jest indeksem 0 tego stringa, bo skąś trzeba zacząć
        {
        paramstr[_j][_k]=u1rxf[rxr]; //przyjmijmy ze masz dwuwymiarową
    //tablice charów - pierwszy indeks to numer parametru, drugi to znaki
    //zawarte w tym parametrze - unsigned char paramstr[5][20]; tutaj
    //przepisuj znaki z głównego stringa do mniejszego na poczatek
        rxr++; _k++; //pomocnicza zmienna _k
        if (u1rxf[rxr]=='-') {_j++; _k=0; rxr++; }; //sprawdż czy bierzący znak to kreska - jesli tak, to zwieksz licznik parametru i wyzeruj licznik znaku w parametrze
        };
    


    Kod powyzszy parsuje łańcuch parametrów zakonczony znakiem pustym na kawałki które w stringu wejsciowym (u1txr) są oddzielone '-'...

    przyklad:

    string zawarty w u1txr z poczatkiem w 0 : "Moj-testowy-parametr\0"

    Po wywołaniu parsera otrzymasz:

    paramstr[0] == "Moj\0"
    paramstr[1] == "testowy\0"
    paramstr[2] == "parametr\0"

    Moze ci jakos pomogłem jesli o to chodziło, jesli nie to pomoze komuś innemu :)

    pozdrawiam

    Dodano po 2 [minuty]:

    Dodaje, że przyjąłem ze tablica paramstr w całości jest wypełniona zerami
  • #18 5220484
    UDMA
    Poziom 16  
    nsvinc napisał:
    _W_TABLICACH_PRZECHOWUJĄCYCH_STRING_STOSUJEMY_UNSIGNED_CHAR_....


    Od kiedy? Widocznie biblioteka string.h jest źle napisana.
  • #19 5220728
    nsvinc
    Poziom 35  
    ->UDMA

    Wyobraź sobie ze standardowy char jest od -128 do 127 tak? Fakt ze STANDARDOWA tabela znaków ASCII jest do 127...ale co wtedy jesli wykorzystujesz rozszerzony ASCII (np. LATIN2)? Chcesz mi powiedzieć ze ktoś zadeklarował -71 znak? Dla bezpieczeństwa powinno się stosować unsigned char. Istnieją biblioteki string.h ktore są napisane dla chara bez znaku i obsluguja latiny, bo standardowe tego nie robią.

    Niedawno napisałem sporo własnych funkcji obracających stringami i jesli ktos chce mogę udostępnić. Funkcje obsługują chara bez znaku wlasnie dla ąęśćżźół itp...:

    StrUp(unsigned char *a);
    StrLw(unsigned char *a);
    StrPokemon(unsigned char *a);
    StrCopyToToken(unsigned char token,unsigned char *src,unsigned char *dest);
    StrCopyToIndex(unsigned int to,unsigned char *src,unsigned char *dest);
    StrCopyFromToToken(unsigned int from,unsigned int to,unsigned char token,unsigned char *src,unsigned char *dest);
    StrLoadCodepage(unsigned char *cp);

    ..i sporo więcej....

    [tak na marginesie: prawie wszystkie LCDki alfanumeryczne (i nie tylko) kozystają z rozszerzonej tablicy ASCII]
  • #20 5220869
    Bigfoot
    Poziom 25  
    nsvinc ma racje ale nie myla sie tak do konca Ci, ktorzy zawsze pisza tylko 'char'. Czesto po prostu kompilator ma domyslnie zaznaczona opcje TRAKTUJ CHAR JAKO UNSIGNED CHAR. I po prostu nawet piszac char kompilator wie, ze chodzi o unsigned char. Jezeli jasno sie okresli signed char - wtedy potraktuje liczbe jako -128:127. Ja jednak nauczony doswiadczeniem na roznych platformach zawsze dla bezpieczenstwa jawnie pisze unsigned char. Radze to tez innym :)

    BF
  • #22 5221204
    mirekk36
    Poziom 42  
    nsvinc -> może się mylę albo czegoś nie wiem , ale jak zacząłem pisać wszędzie "unsigned char" a próbuję coś pisać za pomocą AVR Studio ożenionym z GCC to zaczęły się cyrki z jakimiś warningami.

    okazuje się bowiem, że w AVR Studio a może i GCC tego nie jestem w stanie jeszcze stwierdzić jest chyba domyślnie ustawiony char jako unsigned char

    jak wyłączę ptaszka w parametrach projektu, żeby nie było tak domyślnie to trzeba sobie wtedy oczywiście wszędzie ustawiać na unsigned char. Ale tu znowu ZONK bo jak użyłem funkcji strcpy_P - to znowu warning, że jest niezgodność. Więc zajżałem do "pgmspace.h" a tam jak byk definicja funkcji ze zwykłym char bez unsigned

    extern char *strcpy_P(char *, PGM_P); 


    [AVR][C] jak działać ze stringami lub wskaźnikami

    więc dlatego tylko próbuję wnioskować, że w GCC domyślnie char jest jako unsigned

    - działam dalej, aczkolwiek narazie to wszystko wydaje mi się pokręcone na maxa - choć czuję przez skórę, że jest fajne ;)
  • #24 5221282
    Bigfoot
    Poziom 25  
    nsvinc napisał:
    nie znalzlem takiej opcji w konfiguracji C30 microchipa...


    nsvinc: Radze lepiej zapoznac sie z opcjami kompilatora, ktorego uzywasz (C30)... Ponizej cztery printscreeny z czterech roznych kompilatorow C (C++). Ja szczerze mowiac nie znam takiego, w ktorego opcji by nie bylo wyboru signed/unsigned char... Czasem domyslnie ustawiony jest typ signed, czasem unsigned - ale zawsze do wyboru przez programiste!

    C30
    [AVR][C] jak działać ze stringami lub wskaźnikami

    HiTech PIC
    [AVR][C] jak działać ze stringami lub wskaźnikami

    BB C++
    [AVR][C] jak działać ze stringami lub wskaźnikami

    AVR-GCC
    [AVR][C] jak działać ze stringami lub wskaźnikami

    BF
  • #25 5221372
    mirekk36
    Poziom 42  
    Witam,

    no i po długich jak dla mnie bojach zrobiłem sobie w końcu tę funkcję i mi działa poprawnie. Tylko zapewne jak wy panowie spojrzycie, to od razu dostanie mi się za tą pętlę while(1) w funkcji oraz polecenia break w niej.

    Dla mnie najważniejsze, że się udało, zresztą zgodnie z sugestią kolegi ktrot. Tylko teraz czy mógłby mi ktoś podpowiedzieć jak można się pozbyć tego while(1) i napisać to jakoś może krócej? - tak bardziej w stylu C niż narazie moim ;)


    char napis[20];  // zmienna w RAM (taki buforek)
    char *buf;  // wskaźnik używany do zmiennej napis
    prog_char my_str[] = "ola;domek;kot"; // string w pamięci programu
    
    char * scanstrsp(char* str, char separator)
    {
    	uint8_t i = 0;
    	while( 1 )
    	{
    		if (str[i] == separator)
    		{
    			str[i] = 0;
    			buf = str + i + 1;	
    			break;
    		}
    		if (str[i] == 0)
    		{
    			buf = str + i;
    			break;
    		}
    
    		i++;
    	}
    
    	return str;
    }
    
    
    int main(void)
    {
                    // tu kopiuję sobie z pamięci programu tekst do zmiennej w RAM
    	strcpy_P(napis, my_str);
                     
                    // tu ustawiam wskaźnik buf na początek tablicy ze stringiem do parsowania
    	buf = napis;
    	lcd(napis); // wyświetlam go sobie w 1 linijce w całości
    
    
    	locate(2,1);
    	lcd(scanstrsp(buf, ';'));  // w 2 linijce pojawia się ładnie "ola"
    
    	locate(3,1);
    	lcd(scanstrsp(buf, ';')); // w 3 linijce pojawia się "domek"
    
    	locate(4,1);
    	lcd(scanstrsp(buf, ';'));  // w 4 linijce pojawia się "kot"
    
                    // i tu już wskaźnik buf jest pusty
    
    
    	while(1);
    
    
    	return 0;
    }
  • #26 5221396
    ktrot
    Poziom 20  
    Nieźle. Może będziesz pierwszy na elektrodzie (a w każdym razie jednym z nielicznych), który pisze w C. 99% programów jest C podobne, tzn składnia z C ale myślenia jak w Basicu.
    Tak na szybko to spłodziłem takie coś:

    
    char *par[8];
    char t[]="ab1;cd2;ef3;gh4;tyu5;";
    
    int param()
    { 
    int i=0; int j=0;
      par[0]=t;
      while (t[i])
      {  
      while(t[i++]!=';');
      par[++j]=t+i; 
      t[i-1]=0;
      }
      return j;   
    }
    
    void main()
    {
      int n;
    n=param();    //n zawiera liczbę parametrów
                         //a tablica wskaźników par wskazania 
                         //na poszczególne    parametry
    while(1);
    }
    


    U Ciebie jednak lepsze jest parametryczne wywołanie funkcji, u mnie stały dostęp do parametrów w dowolnej kolejności.
  • #27 5221758
    Freddie Chopin
    Specjalista - Mikrokontrolery
    EDIT - post zedytowany, bo walnalem glupote.

    EDIT: ta czesc zostala wycieta, bo zamiast probowac przerabiac to co masz, lepiej machnac cos, w czym nie ma tego problemu.

    ogolnie petle mozna by zalatwic nieco inaczej, zeby to lepiej dzialalo i nie trzeba bylo kombinowac (break & if)...

    np:

    char * scanstrsp(char* str, char separator) 
    { 
        char* saved_str=str;
        while(*str!=0 && *str != separator) // petla oblicza pozycje separatora, albo koniec stringa
            str++;
        // koniec petli, tzn ze zostal osiagniety albo separator, albo koniec
        buf=((*str)?str+1:str); // jesli to koniec (*str==0), to bufor = adres konca (str), jesli tylko separator (*str!=0) - bufor = znak za separatorem (str+1)
        *str='\0'; // przypisac mozna i tak, bo warunek zajmie wiecej kodu i czasu
        return saved_str; //zwraca zapisana wczesniej wartosc do poczatku mielonego stringa
    }
    


    jesli koniecznie chcesz, to tez da sie przerobic na wersje tablicowa (czyli z indexowaniem po i), ale moim zdaniem nie warto. na 90% to bedzie wydajniejsze

    @√€!!
  • #28 5221811
    Bigfoot
    Poziom 25  
    ktrot napisał:
    Może będziesz pierwszy na elektrodzie (a w każdym razie jednym z nielicznych), który pisze w C.


    Co ty za herezje opowiadasz?

    BF
  • #29 5221859
    mirekk36
    Poziom 42  
    dzięki Fredie -> udoskonaliłem już swoją funkcję:

    char * scanstrsp(char* str, char separator)
    {
    
    	char *rt = str;
    
    	while( (*str) && (*str!=separator) ) str++;
    
    	buf = str;
    
    	if ( *str ) 
    	{
    		*str = 0;
    		buf++;
    	}
    
    	return rt;
    }


    teraz chyba wygląda lepiej - a i w procku zajmuje o 12 bajtów mniej w pamięci programu. Chociaż jak zobaczyłem to parsowanie parametrów jakie podał wyżej kolega ktrot to też jest super rozwiązaniem

    .... coraz bardziej mi się ta zabawa z C podoba
  • Pomocny post
    #30 5221884
    Freddie Chopin
    Specjalista - Mikrokontrolery
    zedytowalem przed sekunda swojego posta finalnie, ale widze ze czytales juz dobra wersje chyba.

    w sumie mozna by ja jeszcze poprawic (polaczyc to wpisywanie \0 do warunku), ale widze ze juz to zrobiles, wiec nie bede wyskakiwal z tym juz <:

    0x41 0x56 0x45!!
REKLAMA