procek87 napisał(a):
Zastanawia mnie po zdefiniowaniu tablicy gdzie jest przetrzymywany ten adres zawarty w nazwie tab ?
Bo przecież nazwa zawiera adres ,na który patrzy wskaźnik do elementu uint8_t tak to odebrałem po przeczytaniu rozdziału o Wskaźnikach.
Asembler odpowiedziałby na moje pytania ale nie znam go i bardzo ciężko mi analizować plik .lss może ktoś pomoże, i opisze co i gdzie się dzieje z tą tablicą w asemblerze
?
Nie zrozum mnie źle. To nie jest jakaś złośliwość czy brak chęci pomocy. Ja już raz odpowiedziałem na Twoje pytanie dość szczegółowo w innym wątku, tylko aby zrozumieć, trzeba już mieć jakąś wiedzę np. dotyczącą budowy i zasady działania mikrokontrolera, jego listy rozkazów, assemblera itp.
Ty tej wiedzy jeszcze nie masz, dlatego nie zrozumiałeś, więc zadajesz następne pytania. Odpowiedź na te pytania zapewne zrodzi następne pytania itd. W ten sposób można napisać na forum całą książkę, a forum do tego nie służy.
Ale OK, spróbuję jeszcze raz (ostatnie podejście), oczywiście w dużym uproszczeniu i postaram się jak najprzystępniej dla początkującego. Opis dotyczy zmiennych globalnych i nie uwzględnia procesu inicjowania wartości zmiennych wartościami podanymi przez programistę, aby nie zaciemniać sprawy
Zmienne lokalne są alokowane na stosie, a to już zupełnie inna historia.
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Kiedy kompilator C napotka taką definicję tablicy myśli sobie tak:
Programista chce mieć do dyspozycji zmienną zmienna_a typu uint16_t. Trzeba zarezerwować odpowiednią ilość bajtów pamięci RAM w pierwszej dostępnej lokalizacji. Aktualnie pierwszym dostępnym adresem jest 0. Zmienna jest 16-bitowa, więc zajmie 2 bajty.Kompilator na podstawie tej definicji robi więc co następuje:
- zapisuje sobie w swojej pamięci podręcznej symbol zmienna_a,
- przypisuje symbolowi adres w pamięci RAM równy początkowi pamięci RAM, np. dla Atmega8 jest to adres 0x0060,
- przypisuje do symbolu rozmiar, który w tym przypadku wynosi 2 bajty,
- zapamiętuje też inne rzeczy, które w tej chwili nie są dla nas bardzo istotne.
Na podstawie następnej definicji robi tak:
- zapisuje sobie w swojej pamięci podręcznej symbol tab,
- przypisuje symbolowi adres w pamięci RAM, który jest sumą adresu poprzedniego symbolu i przypisanego mu rozmiaru, czyli (0x0060+0x02)=0x0062,
- przypisuje do symbolu rozmiar, który w tym przypadku wynosi (8 elementów) * (1 bajt) = 8 bajtów.
Na podstawie następnej definicji robi tak:
- zapisuje sobie w swojej pamięci podręcznej symbol zmienna_b,
- przypisuje symbolowi adres w pamięci RAM, który jest sumą adresu poprzedniego symbolu i przypisanego mu rozmiaru, czyli (0x0062+0x08)=0x006A,
- przypisuje do symbolu rozmiar, który w tym przypadku wynosi 1 bajt.
Na podstawie następnej definicji robi tak:
- zapisuje sobie w swojej pamięci podręcznej symbol wsk,
- przypisuje symbolowi adres w pamięci RAM, który jest sumą adresu poprzedniego symbolu i przypisanego mu rozmiaru, czyli (0x006A+0x01)=0x006B,
- przypisuje do symbolu rozmiar, który w tym przypadku wynosi 2 bajty.
Należy pamiętać o tym, że kompilator do tej pory jeszcze nigdzie żadnego adresu nie umieścił w kodzie, po prostu te adresy sobie pamięta.
Jeśli teraz napotka w kodzie np. taką linijkę:
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
to może wygenerować taki przykładowy kod (sposobów jest oczywiście więcej, więc nigdy nie wiadomo, który sposób kompilator wybierze jako najbardziej optymalny w danym momencie):
język asm
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Jeśli później napotka w kodzie np. taką linijkę:
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
to może wygenerować taki przykładowy kod:
język asm
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Wywołanie funkcji, której argumentem jest wskaźnik do tablicy:
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
będzie wyglądało mniej więcej tak:
język asm
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Jak widać kompilator w momencie napotkania definicji zmiennej (jakiejkolwiek, nie tylko tablicy) nie musi od razu nigdzie zapisywać wartości przydzielonego jej adresu w pamięci RAM. On ten adres po prostu zapamiętuje w swojej pamięci podręcznej na czas kompilacji i wstawia jego wartość do odpowiednich poleceń assemblera jako ich argumenty dopiero w momencie, gdy w kodzie jest odwołanie do danego symbolu.
Oczywiście w rzeczywistości sprawa jest nieco bardziej skomplikowana, ale po szczegóły zapraszam już do wspomnianej wcześniej w innym wątku literatury.
Jeżeli nadal nie zrozumiałeś, to ja się już niestety poddaję. Ponieważ interesują Cię takie szczegóły powinieneś jednak duuużo poczytać o budowie i zasadzie działanie mikrokontrolera, o kodzie maszynowym i instrukcjach ASM, a także o zasadzie działania kompilatora, a wtedy na pewno wszystko się wyjaśni.
Pozdrawiam
Andrzej