Programowanie
Unię tworzymy tyczny sposób jak strukturę. zamiast słowa kluczowego struet używając słowa anion. Do poszczególnych pól unii dostajemy się tak samo jak do pól struktury- Zohac7 przykładowy listing w tej ramce. Na tym jednak podobieństwa się
“ Nm | ||
; - * |
(...l | |
a c |
l '3' | |
uie |
>13 | |
u32 |
57305565 | |
— O |
(...) | |
* |
1 '3' | |
b |
2 '31 | |
H c | ||
[0] l '3' | ||
[1] 2 '31 | ||
[2] 3 '3' | ||
tn * n- |
|b«« d |
[o»ioo |
000100 01 02 03 04 TT TT .. .W |
ś |
000100 rr rr rr rr n rr yyrm | |
oooioc rr rr rr rr rr tr yym? | |
000112 rr rr rr rr rr rr ww |
zi |
kończą Unia umieszcza wszystkie swoje składowe elementy tak. ic norzystają cne zc wspólnego obszaru pamięci. Rozmiar całej unii równy jest rozmiarowi największego pola.
Częstym przeznaczeniem unii jest przechowywanie danych, o których wiemy, źc będziemy korzystać tylko z jednej z nich, a to z której, uzależnione jest od jakichś zdarzeń w programie. Jednak możliwości są szersze - w przykładowym programie w ramce za pomocą tablicy możemy dostać się do poszczególnych bajtów zmiennej 32-bitowej.
Niektórych interesuje, jak dokładnie rozmieszczane są w pamięci dane znajdujące się w unii. Zamiast odpowiadać teoretycznie na to pytanie, proponuję Ci przeprowadzenie symulacji ba nalnego programu widocznego obok.
Po zakończeniu symulacji powinieneś otrzymać wynik widoczny na dołączonych obrazkach. Jednak aby dobrze zrozumieć sprawę, najle- }
piej zobaczyć, co się dzieje ze wszystkimi polami, krok po kroku, przy wpisywaniu kolejnych wartości do tablicy unii
Jeśli zechcemy zainicjować unię początkową wartością, natkniemy się na pewien problem: standard pozwala nam na inicjację tylko pierwszego pola. Jest to sporym utrudnieniem, jeśli chcemy korzystać z unii
#include <inttypes.h>
char c;
ulncie z uint32 t struet {
char a
>5;
uint8 t t[4]
ui6; u32;
int nain(void)
{
u.t[0] * 1 u.t[l] - 2 u.r[2] * 3 u.t[3] - 4
return 0;
umieszczonej w pamięci programu. Istnieją aktualnie dwie możliwości rozwiązania tego problemu:
1. Jako pierwszy umieszczamy element największy
i podczas inicjacji zawsze dokonujemy rzutowania. Rozwiązanie to uia tę zaletę, żc jest zgodne zc standardem Jednak me zawsze możemy łatwo określić, który element jest nąjw iększy. Ponadto, samo rzutowanie czasami powoduje przekształ- union
cenie danej - przykładowo j
zrzutowanie wartości int i;
zmiennoprzecinkowej na float f;
całkowitą. W zapisie }” " {(int)l( :J
Dane w unii zostaną ustawione tak, że pole i przyjmie wartość 10, natomiast pole J będzie zupełnie inne od oczekiwanego.
2. Drugie rozwiązanie wiąże się bezpośrednio z możliwościami, jakie daje AYR-GCC. Nasz kompilator umożliwia jawne podanie pola, które chcemy zainicjować:
Teraz uzyskamy dokładnie to, o co nam chodziło. Mimo tego, że korzystanie z tego zapisu może sprawić, że nasz kod stanie się nudniejszy do przeniesienia, jest na tyle wygodne, że warto z tego rozw iązania czasem skorzysta:.
Na stronie www umieszczam opisane programy przeznaczone do badania zachowania unii.
Przykład: listing 133
l isting 141 - obsługa komunikatu OK oraz ESC w menu | |
case tdm_men:j_esc: goto cleanupj case i DM_MEN'J_OK: | |
1 // Wczytanie do pamięci ram aktualnej pozycji menu MENUITEM menuj neroepy ?(4naenu, pnenu+iiideK-tcurpcs, sizeof(menu)); // Sprawdzenie z czym mamy do czynienia 1f (rrenu. type «= MENUT_POPUP) sy3tem menu(nenu.data.pSubmenu); else if(rrenu.type — MENUT_FUMC) | |
1 i f (rrenu. data. OnSelectProc !■ NULL) | |
1 if (menu .data .OnSelent.Proc(miirpos)) goto cleanupj // Przywracanie parametrów które mogły oy3tcra_lcbdSetRepeótSpccd(8) ; system timerSet(0, SYSTEM TIMER MODEONE 0); ) |
być zmienione CIIOT, 100, |
1 break; |
Listing 143 - funkcje, do których odnosi się menu 1 listingu 141
void app menuLightCraw(FILE* stream, uintlS t idNarr.e)
{
fprintf P(stream, langsys_GetText(idName), (int)oyotcn_LcdLightCct())»
}
uintu t app menuLight(uint8_t curpos)
{
return 0; // Nie kończ nenu
)
z dodatkowym opisem będzie można znaleźć na stronie Elportalu. Dzisiejszy opis starałem się prowadzić przede wszystkim tak, aby sama idea była jasna.
Listing 142 - menu z podmenu oraz wywołaniem funkcji | |
MENUITEM_P a?p_submer.u [] - | |
V {MENUT FUNC, IDS Subl, system menuBaseDzaw, |
{NULL}}, |
{menut FUNC, ids Sub2, system menuBaseoraw, (MENUT END, 0, NULL, {NULL}} ); |
{NULL}}, |
MENUITEM_P app_nainmenu[] -1 | |
( (MENUT FUNC, IDS Light, app mcnuLięhtDraw, |
(.OnSelectFroc«app menuLight}}, |
(MENUT PCPUP, IDS 2Suo, system nenuBaseCraw (...)" |
, {(MENUITEM_P*)app_safcmenu}}, |
Zaproponowałem napisanie dużego programu, jednak jak miałem okazję pokazać pod koniec, programu ten sprawia, że rzeczy złożone stają się łatwe. Rozdzieliliśmy dość wyraźnie elementy aplikacji oraz czegoś, co można nazwać systemem. To duży krok naprzód.
Na stronie www zostanie także umieszczony bardziej rozbudowany przykład pracy z menu.
Na tym etapie skończymy zajmowanie się wyświetlaczem alfanumerycznym.
Radosław Koppel
radoslaw. koppcl@clportal.pl
89CXX 90SXX 74XX 40XX p|C AJ M£GA PCFXX DSXX
Elektronika dla Wszystkich Sierpień 2006 47