ПрограммированиеC разработчик

Расскажите о ключевых отличиях между const и #define для определения констант в языке C. Когда и зачем использовать каждый из подходов, с примерами типовых ошибок?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

#define — это препроцессорная директива, которая просто заменяет все вхождения идентификатора на значение до компиляции. Она не создаёт переменных, не знает о типах, не проверяет границы и не уважает область видимости.

const — это квалификатор, который создаёт настоящую переменную, но заблокированную для записи после инициализации. Переменная const имеет тип, область видимости, участвует в отладке и может быть более безопасной. Такие переменные размещаются в сегменте .rodata или на стеке/в оперативной памяти.

Когда и зачем использовать:

  • #define — для простых скалярных значений, которые нужны на этапе компиляции, особенно если использовать в препроцессорных условиях или размерах массива (#define SIZE 16).
  • const — для значений, которые нужно типобезопасно передавать, дебажить, и при этом безопасно экспортировать (в заголовочных файлах, межмодульно).
  • Для указателей на строки и массивы предпочтительнее использовать const.

Пример:

#define PI 3.14159 const double G = 9.81; int arr[PI]; // ОШИБКА! PI не integer int arr2[G]; // ОШИБКА! G не значение времени компиляции

Вопрос с подвохом.

Вопрос: Работает ли const int a = 10; как константа времени компиляции для создания массива: int arr[a];?

Ответ: Нет. В языке C const — это квалификатор, но переменная создаётся и инициализируется во время выполнения, а не во время компиляции, поэтому размер массива должен быть литералом или выражением, известным компилятору. Используйте #define, либо enum { SIZE = 10 };.

Пример ошибки:

const int a = 5; int arr[a]; // В C89/90 не сработает (VLAs появились в C99, но не везде)

История

В медиа-сервере попытались использовать const int для задания размеров буфера, думая, что это "константа времени компиляции". На одном компиляторе (GCC, C99) всё работало, но на большинстве — ошибка компиляции (VLA не поддерживаются), срочно переписали на #define.


История

В платформо-зависимом коде определяли строку через #define NAME "MyApp", использовали в нескольких местах и забыли заключить в скобки. После добавления к строке символов без явных скобок получали неправильные результаты, приводящие к странным багам в логах.


История

На проекте с несколькими модулями определили константу через #define в двух местах с разными значениями (копипаст). Результат — модули работали с разными константами, нонификации данных, которые исправили только при скрупулёзной отладке.