programowanieProgramista C

Opowiedz o kluczowych różnicach między const a #define w definiowaniu stałych w języku C. Kiedy i po co używać każdego z podejść, wraz z przykładami typowych błędów?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

#define — to dyrektywa preprocesora, która po prostu zastępuje wszystkie wystąpienia identyfikatora na wartość przed kompilacją. Nie tworzy zmiennych, nie zna typów, nie sprawdza granic i nie szanuje zakresu widoczności.

const — to kwalifikator, który tworzy prawdziwą zmienną, ale zablokowaną do zapisu po inicjalizacji. Zmienna const ma typ, zakres widoczności, bierze udział w debugowaniu i może być bardziej bezpieczna. Takie zmienne są umieszczane w segmencie .rodata lub na stosie/w pamięci operacyjnej.

Kiedy i po co używać:

  • #define — dla prostych wartości skalarowych, które są potrzebne na etapie kompilacji, zwłaszcza do użycia w warunkach preprocesora lub rozmiarach tablic (#define SIZE 16).
  • const — dla wartości, które trzeba bezpiecznie typować, debugować oraz bezpiecznie eksportować (w plikach nagłówkowych, między modułami).
  • Dla wskaźników na ciągi i tablice preferencyjnie należy używać const.

Przykład:

#define PI 3.14159 const double G = 9.81; int arr[PI]; // BŁĄD! PI nie jest całkowite int arr2[G]; // BŁĄD! G nie jest wartością czasu kompilacji

Pytanie z podstępem.

Pytanie: Czy działa const int a = 10; jako stała czasu kompilacji do tworzenia tablicy: int arr[a];?

Odpowiedź: Nie. W języku C const — to kwalifikator, ale zmienna jest tworzona i inicjowana w czasie wykonania, a nie w czasie kompilacji, dlatego rozmiar tablicy musi być literałem lub wyrażeniem znanym kompilatorowi. Użyj #define, albo enum { SIZE = 10 };.

Przykład błędu:

const int a = 5; int arr[a]; // W C89/90 nie zadziała (VLA pojawiły się w C99, ale nie wszędzie)

Historia

Na serwerze multimedialnym próbowano używać const int do określenia rozmiarów bufora, myśląc, że to "stała czasu kompilacji". Na jednym kompilatorze (GCC, C99) wszystko działało, ale w większości — błąd kompilacji (VLA nie są wspierane), pilnie przepisali na #define.


Historia

W kodzie zależnym od platformy określono ciąg przez #define NAME "MyApp", używano w kilku miejscach i zapomniano o nawiasach. Po dodaniu do ciągu znaków bez wyraźnych nawiasów otrzymywano błędne wyniki, prowadzące do dziwnych błędów w logach.


Historia

W projekcie z kilkoma modułami określono stałą przez #define w dwóch miejscach z różnymi wartościami (copy-paste). Wynik — moduły działały z różnymi stałymi, a normalizacja danych, które naprawiono dopiero przy skrupulatnym debugowaniu.