Podczas przeglądania kodu stosuję następujące zasady:
Zawsze używaj const
parametrów funkcji przekazywanych przez odniesienie, gdy funkcja nie modyfikuje (ani nie zwalnia) wskazanych danych.
int find(const int *data, size_t size, int value);
Zawsze używaj const
dla stałych, które w innym przypadku mogłyby zostać zdefiniowane za pomocą #define lub enum. W rezultacie kompilator może zlokalizować dane w pamięci tylko do odczytu (ROM) (chociaż linker jest często lepszym narzędziem do tego celu w systemach osadzonych).
const double PI = 3.14;
Nigdy nie używaj const w prototypie funkcji dla parametru przekazywanego przez
wartość . Nie ma to znaczenia i dlatego jest po prostu „hałasem”.
// don't add const to 'value' or 'size'
int find(const int *data, size_t size, const int value);
W stosownych przypadkach użyj const volatile
w miejscach, których program nie może zmienić, ale może się zmienić. Rejestry sprzętowe są tutaj typowym przypadkiem użycia, na przykład rejestr stanu odzwierciedlający stan urządzenia:
const volatile int32_t *DEVICE_STATUS = (int32_t*) 0x100;
Inne zastosowania są opcjonalne. Na przykład parametry funkcji w ramach implementacji funkcji można oznaczyć jako const.
// 'value' and 'size can be marked as const here
int find(const int *data, const size_t size, const int value)
{
... etc
lub funkcja zwraca wartości lub obliczenia, które są uzyskiwane, a następnie nigdy się nie zmieniają:
char *repeat_str(const char *str, size_t n)
{
const size_t len = strlen(str);
const size_t buf_size = 1 + (len * n);
char *buf = malloc(buf_size);
...
Te zastosowania po const
prostu wskazują, że nie zmienisz zmiennej; nie zmieniają sposobu ani miejsca przechowywania zmiennej. Kompilator może oczywiście zorientować się, że zmienna się nie zmienia, ale dodając const
pozwalasz na wymuszenie tego. Może to pomóc czytelnikowi i zwiększyć bezpieczeństwo (chociaż jeśli twoje funkcje są wystarczająco duże lub skomplikowane, że robi to wielką różnicę, prawdopodobnie masz inne problemy). Edytuj - np. gęsto zakodowana funkcja 200-liniowa z zagnieżdżonymi pętlami i wieloma długimi lub podobnymi nazwami zmiennych, wiedząc, że niektóre zmienne nigdy się nie zmieniają, może znacznie ułatwić zrozumienie. Takie funkcje zostały źle zaprojektowane lub utrzymane.
Problemy z const
. Prawdopodobnie usłyszysz termin „zatrucie ciągłe”. Dzieje się tak, gdy dodanie const
do parametru funkcji powoduje propagację „stałości”.
Edycja - zatrucie const: na przykład w funkcji:
int function_a(char * str, int n)
{
...
function_b(str);
...
}
jeśli zmienimy str
na const
, musimy wtedy upewnić się, że fuction_b
również trwa const
. I tak dalej, jeśli function_b
przekaże to str
dalej function_c
, itd. Jak można sobie wyobrazić, może to być bolesne, jeśli rozprzestrzeni się na wiele oddzielnych plików / modułów. Jeśli propaguje się do funkcji, której nie można zmienić (np. Biblioteki systemowej), konieczne jest rzutowanie. Więc przelewanie
const
się w istniejącym kodzie może być przyczyną problemów. Jednak w nowym kodzie najlepiej jest const
konsekwentnie kwalifikować się w stosownych przypadkach.
Bardziej podstępnym problemem const
jest to, że nie było w oryginalnym języku. Jako dodatek nie do końca pasuje. Na początek ma dwa znaczenia (jak w powyższych regułach, co oznacza „nie zamierzam tego zmieniać” i „tego nie można zmienić”). Ale co więcej, może być niebezpieczne. Na przykład skompiluj i uruchom ten kod i (w zależności od kompilatora / opcji) może się on zawiesić po uruchomieniu:
const char str[] = "hello world\n";
char *s = strchr(str, '\n');
*s = '\0';
strchr
zwraca char*
nie a const char*
. Jak sama rozmowa jest parametr
const
musi rzucać parametr wezwanie do char*
. I w tym przypadku odrzuca to właściwość pamięci tylko do odczytu. Edycja: - dotyczy to ogólnie zmiennych w pamięci tylko do odczytu. Przez „ROM” rozumiem nie tylko fizyczną pamięć ROM, ale każdą pamięć chronioną przed zapisem, tak jak dzieje się w przypadku sekcji kodu programów działających na typowym systemie operacyjnym.
Wiele standardowych funkcji bibliotecznych zachowuje się w ten sam sposób, więc uważaj: gdy masz prawdziwe stałe (tj. Przechowywane w pamięci ROM), musisz bardzo uważać, aby nie stracić ich stałej.
Specific issues with software development
. Jestem dość specyficzny.