W tym poście chciałbym opisać sposób inicjalizacji tablic oraz struktur.
Tablice:
Podstawowym sposobem na inicjalizację tablic jest następujący zapis:
- uint8_t val[rozmiar] = {0x00};
Przy czym należy tutaj pamiętać, że tablicę w taki sposób można zainicjalizować jedynie przez wpisanie do niej wartości zero. Nie można do wszystkich komórek wpisać innej wartości. Przykład poniżej:
- int main(void)
- {
- uint8_t val[100] = {0x01};
- for(uint8_t i=0; i<5; i++)
- {
- printf("%u ", val[i]);
- }
- return 0;
- }
Ten prosty program zwróci takie wartości:
1 0 0 0 0
Wartość 0x01 dotyczy tylko i wyłączenie pierwszego elementu. Pozostałe elementy domyślnie przyjmą wartość 0.
Wobec tego aby zainicjalizować tablicę wartościami innymi niż 0 pozostaje jedna z kilku opcji:
Wpisywanie ręczne:
W ten sposób dane wprowadzamy ręcznie jak poniżej:
- uint8_t tablica[rozmiar] = {100, 85, 73, 84, 5, 8};
Można w takim przypadku nie podawać wielkości tablicy:
- uint8_t tablica[] = {100, 85, 73, 84, 5, 8}; //Rozmiar 6
Wtedy jej rozmiar należy pobrać wykorzystując operator sizeof(). W przypadku typu uint8_t wystarczy wywołać go następująco:
- sizeof(tablica);
Jeśli tablica jest innego typu np. uint16_t, int (typ danych większy niż jeden bajt). To pobranie danych o rozmiarze należy zmodyfikować:
- (sizeof(tablica)/sizeof(typ_danych_tablicy))
- np. (sizeof(tablica)/sizeof(uint16_t))
W przypadku niepełnego zdeklarowania wartości, jak w przypadku drugiego przykładu, dane zostaną uzupełnione zerami. Tym razem rozmiar tablicy należy wprowadzić do funkcji
- uint8_t tablica[10] = {100, 85, 73, 84, 5, 8};
Wartości od [6] do [9] przyjmą wartość 0 automatycznie.
Pętla:
Każda iteracja w pętli wpisuje kolejny element do tablicy:
- for(uint8_t i=0; i<100; i++)
- {
- val[i] = i;
- }
Memset:
- memset(val, 25, 100);
Memset ustawia zadaną ilość bajtów od wskazanego miejsca, więc w przypadku typu składającego się z większej ilości bajtów należy zmodyfikować funkcję następująco:
- memset(val, 0x00, sizeof(val)/sizeof(val[0]));
Jako trzeci parametr należy podać ilość bajtów w tablicy.
Tutaj pojawia się natomiast problem wprowadzania danych do komórek. Jak wspomniałem wcześniej dane wpisywane są do każdego bajtu. Co oznacza, że po wprowadzaniu wartości np. 0x01 dla uint16_t czy int wartość elementu nie będzie odpowiadała prawdopodobnej wartości oczekiwanej.
Typy danych inne niż jednobajtowe powinny mieć wpisywane wartości raczej z użyciem pętli for/while niż memset. Chyba, że chcemy tylko wyzerować tablicę. W innym przypadku należy się upewnić, że funkcja zadziała tak jak należy.
GCC:
W poniższym przykładzie wartości od 0 do 5 przyjmą wartość 1. Pozostałe elementy zostaną ustawione na zero.
- uint8_t val[100] = {[0 ... 5] = 0x01};
Można także inicjalizować pojedyncze wartości:
- uint8_t tablica[100] = {[4] = 0x01, [7] = 0x30};
Tablica powyżej będzie zawierała wartości niezerowe dla pola [4] oraz [7].
Można też rozpocząć inicjalizację od zadanej pozycji:
- uint8_t tablica[100] = {[4] = 0x01, 30, 40, 80, 120};
Dla powyższej deklaracji wartości od pozycji [4] do [8] zostaną ustawione wartości niezerowe.
Rozmiar tablicy:
Najczęściej tablice, zwłaszcza globalne, muszą być wykorzystując stałą liczbową.
- #define ROZMIAR 10
- uint8_t val[ROZMIAR] = {0x00};
W przypadku przekazywania rozmiaru tablicy do funkcji, nie można tego dokonać w następujący sposób.
- void initArray(uint8_t rozmiar)
- {
- uint8_t val[rozmiar] = {0x00};
- for(uint8_t i=0; i<rozmiar; i++)
- {
- printf("%u\r\n", val[i]);
- }
- }
Tablica musi najpierw musi zostać zdeklarowana, po czym można do niej wprowadzać wartości.
- void initArray(uint8_t rozmiar)
- {
- uint8_t val[rozmiar];
- for(uint8_t i=0; i<rozmiar; i++) {
- val[i] = i;
- }
- for(uint8_t i=0; i<rozmiar; i++) {
- printf("%u\r\n", val[i]);
- }
- }
Dla powyższego przypadku należy pamiętać, że tablica val jest to zmienną tymczasowa i zostanie ona alokowana na stosie. Jeśli tablica val zostanie zdeklarowana jako static to taka operacja jak w funkcji powyżej się nie uda. Ponieważ tablica globalna musi być zainicjalizowana jako tablica o stałym rozmiarze.