programowanieEmbedded C programista

Opisz cechy pracy z modyfikatorem const dla parametrów funkcji i zmiennych lokalnych w C. Jak const wpływa na przekazywanie wskaźników i referencji do danych, i jaka jest różnica między różnymi modyfikacjami const w deklaracjach funkcji?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

const w języku C umożliwia ograniczenie modyfikowalności obiektu. Pracując z parametrami funkcji, pomaga to chronić dane przed przypadkowymi zmianami. Kluczowa różnica w deklaracji zależy od tego, do czego odnosi się modyfikator const i gdzie się znajduje względem wskaźnika.

Przykład różnych deklaracji:

void func(const int *ptr); // wskaźnik na stały int void func(int * const ptr); // stały wskaźnik na int void func(const int * const ptr); // stały wskaźnik na stały int
  • const int *ptr — dane są niezmienne, sam wskaźnik można przypisać na nowo.
  • int *const ptr — dane są zmienne, ale wskaźnika nie można przypisać na nowo.
  • const int *const ptr — ani dane, ani wskaźnik nie mogą być zmieniane wewnątrz funkcji.

Poprawne użycie const: pozwala:

  • wyraźnie wyrażać zamiary programisty,
  • uprościć czytanie i utrzymanie kodu,
  • tworzyć bezpieczne interfejsy do pracy z pamięcią.

Przykład kodu

void print_array(const int *arr, size_t n) { for (size_t i = 0; i < n; ++i) { printf("%d\n", arr[i]); // arr[i] = 10; // błąd: próba zmiany danych const } }

Pytanie z podpowiedzią

Pytanie: Czy można przypisać adres zmiennej stałej do zwykłego wskaźnika?

Oczekiwany błędny odpowiedź: "Tak, jeśli usuniesz const w deklaracji wskaźnika, kompilator na to pozwala."

Poprawna odpowiedź: Dopuszczalne jest "obniżenie const" tylko z wyraźnym rzutowaniem typów (casting), ale prowadzi to do undefined behavior przy próbie zmiany obiektu zadeklarowanego jako const. Nie można tego robić — narusza to semantykę const i prowadzi do błędów w czasie wykonania.

Przykład:

const int x = 5; int *ptr = (int*)&x; *ptr = 10; // UB: zmiana obiektu const

Przykłady rzeczywistych błędów z powodu nieznajomości niuansów tematu


Historia

W dużym projekcie programista próbował obejść ochronę const, rzutując wskaźnik const na zwykły i modyfikując dane w segmencie pamięci tylko do odczytu. Na niektórych platformach doprowadziło to do awaryjnego zakończenia programu (segmentation fault), a na innych — do niezauważalnych błędów, trudnych do debugowania.


Historia

W bibliotece do pracy z tablicą programista zapomniał zadeklarować parametry jako const. W rezultacie nieprawidłowe wywołanie funkcji przypadkowo zmieniło dane źródłowe, co doprowadziło do niesynchronizacji stanu tablicy i poważnych błędów w kolejnych blokach przetwarzania.


Historia

Podczas pisania funkcji callback przekazywanej do cudzej biblioteki, zapomniano specyfikować const dla bufora wejściowego. Biblioteka próbowała zmienić dane w stałej linii, co spowodowało awarię na niektórych systemach operacyjnych i długotrwałe rozważania na temat źródła problemu.