EDYCJA: mikrotherion daje doskonałą odpowiedź, która koryguje niektóre moje uwagi tutaj, szczególnie dotyczące zużycia pamięci.
Jak już zidentyfikowałeś, są pewne sytuacje, w których musisz użyć a #define
, ponieważ kompilator nie zezwala na const
zmienną. Podobnie, w niektórych sytuacjach jesteś zmuszony używać zmiennych, na przykład gdy potrzebujesz tablicy wartości (tzn. Nie możesz mieć tablicy #define
).
Istnieje jednak wiele innych sytuacji, w których niekoniecznie istnieje jedna „poprawna” odpowiedź. Oto kilka wskazówek, których chciałbym przestrzegać:
Bezpieczeństwo typu
Z ogólnego punktu widzenia programowania const
zmienne są zwykle preferowane (tam, gdzie to możliwe). Głównym tego powodem jest bezpieczeństwo typu.
#define
(Preprocesor makro) bezpośrednio kopie wartości dosłownym do każdej lokalizacji w kodzie, dzięki czemu każdy niezależnie użytkowania. Może to hipotetycznie prowadzić do niejednoznaczności, ponieważ typ może zostać rozwiązany w różny sposób w zależności od tego, jak / gdzie jest używany.
const
Zmienna jest zawsze tylko jeden typ, który jest określony przez jego deklaracji, a rozwiązany podczas inicjalizacji. Często będzie wymagało jawnego obsady, zanim będzie się zachowywać inaczej (chociaż istnieją różne sytuacje, w których można go bezpiecznie promować domyślnie). Kompilator może przynajmniej (jeśli poprawnie skonfigurowany) emitować bardziej niezawodne ostrzeżenie, gdy wystąpi problem z typem.
Możliwym obejściem tego problemu jest dołączenie jawnej rzutowania lub sufiksu typu w pliku #define
. Na przykład:
#define THE_ANSWER (int8_t)42
#define NOT_QUITE_PI 3.14f
Takie podejście może potencjalnie powodować problemy ze składnią w niektórych przypadkach, w zależności od tego, jak jest używane.
Zużycie pamięci
W przeciwieństwie do obliczeń ogólnego przeznaczenia, pamięć jest oczywiście cenna w przypadku czegoś takiego jak Arduino. Używanie const
zmiennej vs. #define
może mieć wpływ na to, gdzie dane są przechowywane w pamięci, co może zmusić cię do użycia jednego lub drugiego.
const
zmienne będą (zwykle) przechowywane w SRAM, wraz ze wszystkimi innymi zmiennymi.
- Używane dosłownie wartości
#define
będą często przechowywane w przestrzeni programu (pamięć Flash) obok samego szkicu.
(Należy pamiętać, że istnieją różne rzeczy, które mogą wpływać dokładnie na to, jak i gdzie coś jest przechowywane, takie jak konfiguracja i optymalizacja kompilatora.)
SRAM i Flash mają różne ograniczenia (np. Odpowiednio 2 KB i 32 KB dla Uno). W przypadku niektórych aplikacji dość łatwo jest zabraknąć SRAM, więc może być pomocne przejście niektórych rzeczy na Flash. Odwrotna sytuacja jest również możliwa, choć prawdopodobnie mniej powszechna.
PROGMEM
Możliwe jest uzyskanie korzyści z bezpieczeństwa typu przy jednoczesnym przechowywaniu danych w przestrzeni programu (Flash). Odbywa się to za pomocą PROGMEM
słowa kluczowego. Nie działa dla wszystkich typów, ale jest powszechnie używany do tablic liczb całkowitych lub ciągów.
Ogólny formularz podany w dokumentacji jest następujący:
dataType variableName[] PROGMEM = {dataInt0, dataInt1, dataInt3...};
Tabele ciągów są nieco bardziej skomplikowane, ale dokumentacja zawiera pełne szczegóły.