Jako ze guru wiedzy na temat C jeszcze nie jestem (ale zamierzam ;-))) ), wynalazlem pewien problem ktory mnie meczy. Mianowicie w programie definiuje znaki LCD za w nastepujacy sposob:
No i problem. Mianowicie wartosc wyliczona przez (&polish_chars+f) w pierwszym odczycie daje poprawnie wartosc 0x22, jednak w kolejnym kroku kompilator zwieksza Z nie o jeden jak powinien lecz o 0x31 (cos jakby wartosc '1' w ASCII). Popelniam jakis blad ??
Za to ten programik dziala poprawnie. Z jest zwiekszane o 0x01.
Moze mi ktos wytlumaczyc czy to ja robie zle czy co ? Z gorki dzieki.
Didn't find your answer? Ask the community — no account required.
M
Milosz Skowyra
Juz sam wiem, olalem warninga kompilatora i zapomnialem o zrzutowaniu wskaznika na integera ;-)
powinno byc lcd_port=pgm_read_byte(((int)&polish_chars)+f); I dziala ;-)
A
Andy
U¿ytkownik "Milosz Skowyra" snipped-for-privacy@wp.pl napisa³ w wiadomo¶ci news: snipped-for-privacy@wp.pl...
a nie mogl bys tej tablicy jakos po ludzku indeksowac ? :-)
polish_chars[ f ]
tak jest chyba najbardziej naturalnie
K
Krzysztof Rudnik
- w takim ukladzie moze ci adrument zwiekszac w sizeof(polish_chars), wyrzuc ten &. Wtedy argumentami pgm_read_byte beda kolejne adresy zaczynajac od &polish_chars[f]. Mozna tez tak zapisac. W C dodanie liczby n do pointera tworzy pointer przesuniety o n - elementow tablicy. Ty dodajesz liczba do adresu calej tablicy, a nie do adresu jej pierwszego elementu.
Podsumowujac:
&polish_chars[f] - adres f-tego elementu tablicy polish_chars+f - tyle samo
&polish_chars+f - adres f-tej tablicy
Krzysiek Rudnik
T
Tomq
nie jestem specem, ale kiedy¶ chcia³bym byæ. proszê mnie o¶wieciæ dlaczwgo "int" ? przecie¿ tablica by³a definiowana jako "unsigned char" "f" równie¿, sk±d i po co " int " ?
J
J.F.
Bo sa dwa problemy: a) .. '51 .. kto wie jaki rozmiar ma wskaznik, byc moze tylko 1 bajt ? Wiec wskaznik plus char moze sie ograniczac do 256.
b) kolega przekombinowal [a raczej nie przeczytal pewnej ksiazki :-)] polish_chars+f powinno dzialac dobrze. ale &polish_chars wskazuje na cala tablice i ma rozmiar jej calej, wiec &polish_chars+1 to adres calej kolejnej tablicy, a nie drugiego elementu ..
J.
M
Milosz Skowyra
Czytam powoli... i podpieram sie dodatkowo kieszonkowym leksykonem C++. Tyle tylko ze nie dopisalem kontekstu programu. Po prostu mam tablic definicji znakow kilka i dodatkowo sa troche porozrzucane po flashu. Korzystajac z jednej procedury chce wczytac jedna wybrana z nich. Dlatego tak mi bylo wygodniej. Poza tym ten zapis jest dla mnie bardziej czytelny. Ale moze sie myle. Ja go rozumiem tak: pgm_read_byte(((int)&polish_chars)+f); odczytaj z pamieci ROM bajt z adresu (gdzie adres=adres poczatku tablicy polish_chars, powiekszony o f). Poniewaz pgm_read_byte() operuje na int to rzutuje polish_char na inta i dodaje f jako char-a. W programie dla jednej tablicy co prawda wystarczylby char, ale dla kilku juz nie ;-)
Dziala, zezarl 20 bajtow wiecej ;-)
Zaraz... bo sie pogubilem. Zalozmy ze mam tablice char tab[20]; I teraz zeby dostac sie do 10 elementu moge uzyc: a) char x=tab[9] b) Znalezc adres tablicy i dodac offset czyli char x=(((int)&tab)+10); c) Wskaznik na poczatek tablicy i zwiekszyc go o 10 i odczytac. char *x;
*x=&polish_chars; *x+=10;
Jesli jest tak jak piszesz o rozmiarze to dlaczego sizeof(&polish_chars) daje 2 ? To znaczy dla mnie to jasne bo wynikiem jest adres ktory jest integerem wiec ma rozmiar 2. Myle sie ??
Tu sie zgodze.
M
Milosz Skowyra
Tylko ze nie bardzo chce dzialac ;-) W R14 i R15 jest adres poczatku tablicy.
MOV R31,R15 MOV R30,R14 ;to niby poprawnie, do Z wpisuje pocz.tablicy LD R24,Z+ ;w dziwny sposob zwieksza Z o jeden i czyta ;bajt z RAMU spod adresu poczatku tablicy w ROM MOV R14,R30 ;zrzuca adres tablicy +1 MOV R15,R31 MOV R30,R24 ;i gdyby nie wykonal tego to LPM odczytalo by CLR R31 ;poprawna wartosc, a tak dostajemy krzaczki. LPM
M
Milosz Skowyra
Zgadza sie. Co prawda po przeczytaniu kilku postow mam maly metlik, ale sprobuje usystematyzowac. &polish_chars - to adres poczatku tablicy. Jesli zrobie *x=&polish_chars to wskaznik *x wskazuje na poczatek tablicy. Poprawnie ??
Dzieki... dobrze mysle tylko nie potrafie tego jeszcze dobrze w C zapisac ;-(
J
J.F.
Ta dziwnosc moze byc sprytnoscia - jesli rozpoznal ze w kolejnych obiegach petli siegasz do kolejnych komorek pamieci, to jest to prawidlowa kompilacja.
A nie przekombinowales znowu ? Moze masz lcd_port=pgm_read_byte(polish_chars[f]);
Ogolnie C dziala tak, ze (wsk+liczba) ma wartosc liczbowa adres(wsk) + liczba*sizeof(*wskaznik)
Innymi slowy - trzeba pilnie uwazac na typ na ktory wskaznik wskazuje, bowiem dodajemy rozne wartosci. Ale to jest dla wygody, dzieki temu t[i] jest dokladnie tym samym co *(t+i)
Owszem, z tym ze :
- wystarczy pgm_read_byte(((int)polish_chars)+f) - polish_chars i &polish_chars to sa te same adresy, roznia sie natomiast wielkoscia obiektu wskazywanego [co tu nie ma znaczenia]
- w innym procku relacje miedzy wskaznikiem a integerem moga byc inne, wiec zaleca sie nie dokonywac takiej konwersji.
- akurat w AVR byc moze ta funkcja faktycznie ma parametr int, a nie char*.
A to ciekawe. Zglos moze te uwagi supportowi, moze poprawia.
Nie - tak to oliczyles adres [zly!], nie pobrales natomiast zlokalizowanej tam danej, czemu sluzy *
x=*(((int)&tab)+9) a dokladniej, to by wypadalo napisac
x=*( (char*) (((int)&tab)+9));
to samo moglbys zapisac jako
x=*( (char*) (((int)tab)+9)); x=*( tab+9 );
Czy nawet 9[x] - co z definicji wynosi *(9+tab)
Tu glupoty jakies piszes:-)
char *x;
OK, x jest wskaznikiem, czyli adresem, komorki pamieci zawierajacej znak. x jest oczywiscie zmienna, czyli zajmuje dwa bajty w tym procku. x chwilowo jest niezainicjowany, czyli wskazuje w losowo wybrane miejsce pamieci [starsze C wymagaly zeby takie zmienne globalne byly wstepnie zerowane].
*x=&polish_chars;
To jest glupota totalna, bo w ten jeden znak _wskazywany_ przez x [czyli chwilowo w jakies losowe miejsce w pamieci :-)] usilujesz wpisac adres tablicy - czyli pewnie tylko mlodszy bajt adresu.
*x+=10;
A niniejszym usilujesz do znaku wskazywanego przez x dodac 10.
Z sensem wygladaloby to tak: char *x; //wskaznik x=&polish_chars; //teraz wskazuje na poczatek tablicy x+=3 //teraz wskazuje na 4 znak tablicy
*x+=5 // a teraz ten znak powiekszamy o 5
Gdyby w tablicy bylo "ABCDEFGHI", to po wykonaniu zrobiloby sie "ABCIEFGHI" ... gdyby to nie byl ROM.
Bo polish_chars jest tablica, i rozmiar ma chocby i 64. Ale &polish_chars jest juz tylko adresem, a ten liczy 2 bajty.
Natomiast kompilator pamieta na co &polish_chars wskazuje, wiec &polish_chars+1 to bynajmniej nie jest ten sam adres co polish_chars+1.
Nawiasem mowiac - moglbys to zrobic tak:
char * dp;
dp=polish_chars; // lub jak wolisz dp=&polish_chars ; for (unsigned char f=1;f<64;f++) { lcd_port=pgm_read_byte(dp); dp++; // lub wrecz lcd_port=pgm_read_byte(dp++);
data_port |= (unsigned char)_BV(rs); [...] }
Tracisz 2 bajty RAM na dodatkowa zmienna [zreszta niekoniecznie], ale byc moze zyskujesz cos na programie - o ile powiekszenie wskaznika jest w danym procku prostsza operacja niz dodanie dwoch liczb 16 bit..
A swoja droga - o ile kompilator pozwala zdefiniowac taka tablice w obszarze pgm, to imho powinien poprawnie komplilowac po prostu polish_chars[f] - albo cos o tym pisze w faq, albo trzeba serwis powiadomic..
J.
J
Jan Dubiec
[.....]
Na mój gust to są dwa różne adresy - polish_chars jest adresem obszaru pamięci w którym umieszczone są obiekty typu char (czyli polish_chars to jest po prostu typu char *), natomiast &polish_chars jest adresem adresu w/w obszaru czyli mówiąc inaczej jest typu char **, albo jescze inaczej, jest wskaźnikiem na wskaźnik. :-)
[.....]
Nie chce mi się odpalać kompilatora ale jestem pewien że żadna z powyższych konstrukcji nie zadziała tak jak oczekiwano. :-)
Drugie wyrażenie będzie działać, pierwsze nie zawsze. Ale one nie są równoważne tym dwóm wcześniejszym.
Poza tym w zasadzie warto byłoby sprecyzować w tej dyskusji (i w świetle tego co napisałem na samym początku) co to znaczy "znaleźć adres tablicy". Bo jeśli chodzi o adres obszar pamięci w którym znajdują się przechowywane obiekty, to wartość zmiennej tab (pisanej bez żadnych indeksów) jest właśnie tym adresem i nic nie trzeba szukać.
[.....]
^- powinno być tez tego ampersanda
Regards, /J.D.
J
J.F.
Nie - pamietaj ze polish_chars jest tablica ! wiec "jej wartosc liczbowa" jest adresem pierwszego elementu, i pokrywa sie z adresem calosci.
Powinny.
Zgodze sie - potrafia byc niuanse. Ale czesto int sie pokrywa ze wskaznikiem - i wtedy powinno zadzialac.
Poza tym drobnym zastrzezeniem - sa.
Dokladnie. Wiec tab==&tab - choc sa miedzy nimi roznice typu i nie zachowuja sie tak samo.
Aha - to dotyczy rzeczywistej deklaracji tablicy, bo deklaracja w naglowku funkcji jest wskaznikiem..
J.
J
Jan Dubiec
[.....]
Rzeczywiście, masz rację co widać na załączonym przykładzie:
Niby do tab1 i tab2 można odwoływać się w ten sam sposób, tj. przy pomocy indeksów lub arytmetyki wskaźników ale jednak są pewne niuanse w działaniu operatora &. :-) Używając C trzeba być jednak czujnym przez cały czas. :-)
Nie bardzo rozumiem. Może jakiś przykład?
Regards, /J.D.
P
Piotr Wyderski
Wiesz, w C tablice indeksuje sie poczynajac od 0. :-) Poza tym postinkrementacji nalezy uzywac tylko gdy naprawde trzeba; w przeciwnym przypadku nalezy uzyc preinkrementacji: ++f. W tym przypadku nie ma to znaczenia, ale jesli zaczniesz programowac w C++, to zobaczysz roznice, gdy sobie przeciazysz ++.
Scisle rzecz biorac nie popelniasz bledu, ale napisales kompilatorowi nie ten program o ktorym myslales. :-) Kazesz mu wziac adres poczatku f-tej _tablicy_, a nie adres f-tego _elementu_ tej tablicy. Natomiast to
0x31 do niczego mi nie pasuje: masz 49 elementow w tablicy?
No chyba zartujesz. :-) Dlaczego nie uzyjesz
const unsigned char* g = polish_chars;
?
Pozdrawiam Piotr Wyderski
PS. Cos wspominales o przejsciu na uprawe marchewki. ;-)))
P
Piotr Wyderski
Wcale nie, to Ty nie przeczytales tego warninga i nie zamieniles integera na char*. Przykro mi, dopisujac "brakujace" rzutowanie Ty nie naprawiles tego programu, Ty zgwalciles kompilator. :->
Pozdrawiam Piotr Wyderski
M
Milosz Skowyra
Tia, w probnej wersji bylo tylko 49 elementow. Teraz juz kumkam.
Wlasnie kombajn do zbiorow konstruuje ;-))
M
Milosz Skowyra
Bez przesady, szybciej bedzie mu zrobic adiw z,1 bo nie bedzie przelewal Z w rejestry tam i spowrotem.
Dokladnie tak, bo tak sugerowal Andy ;-)
M
Milosz Skowyra
Robi sie... problem tylko ze co innego czytalem a co innego rozumialem ;-((( Znaczy sam sie w pole (marchewki) wyprowadzilem.
[...]
I juz kumam. Nie wiem dlaczego ale caly czas lazilo mi po glowie ze jak operujemy na wskazniku to na wskazniku, czyli jak mamy char *x; to wszystkie operacje tycza sie *x. Teraz wiem ze operacje na zawartosci wskazywanej zmiennej odbywa sie przez dereferencje. Jeszcze ostatnia niejasnosc... char x[20],y[20],a; char *xptr; xptr=&x; //###### a=*xptr; //w a laduje element x[0]
xptr=&x+1; //###### a=*xptr; //w a laduje element y[0]
xptr=x; a=*xptr; //w a laduje element x[0]
xptr=x+1; a=*xptr; //w a laduje element x[1]
juz mysle dobrze czy nadal gdzies blad w logice ?? I jeszcze jedno. Kompilacja tego powyzej daje w liniach oznaczonych ##### warninga "main.c:16: warning: assignment from incompatible pointer type". Mam racje ze chodzi o to ze 2 bajtowy pointer nie miesci sie w char-ze ??
To chyba wlasnie pojalem ;-)
Jak dziala polish_chars[f] to juz podalem ;-)
J
J.F.
Nic na sile ... wszystko mlotkiem :-)
J.
Join the Discussion
Have something to add? Share your thoughts — no account required.
Didn't find your answer?
Ask the community — no account required
Report Content
You are reporting this content to the moderators. They will look at it
ASAP.