Спецификаторы const, volatile и extern.

Давно уже собирался и вот решил сделать небольшую шпаргалку по основным спецификаторам, к помощи которых можно и нужно прибегать при программировании. Без лишних слов, сразу же, переходим к сути.

Квалификатор типа const.

Все переменные, определенные с использованием этого ключевого слова не могут изменить своего значения во время выполнения программы. На то они и константы 😉 Чаще всего спецификатор const используется так: когда в программе много раз используется одно и то же числовое значение, создается переменная, имеющая определенное имя, значение которой равно этому числовому значению. Так как переменная не меняется при выполнении программы, используется ключевое слово const. И теперь вместо использования числового значения можно использовать имя константы, что заметно облегчает понимание написанного кода и последующую работу с ним. Поэтому настоятельно рекомендуется в качестве имен переменных использовать что-либо осмысленное, а не просто первый пришедший на ум набор букв. Например, нужно объявить константу, которая будет хранить значение максимального количества принятых байт. Тогда:

// Удачное имя переменной
const int maxNumOfBytes = 64;
// Неудачное имя переменной
const int var123 = 64;

В принципе это основное применение спецификатора const, поэтому, думаю, нет смысла углубляться, так что идем дальше.

Квалификатор типа volatile.

Этот замечательный спецификатор позволяет нам использовать переменную, значение которой может изменяться неявно в процессе выполнения программы. Что же это значит? А вот пример:

bool test = FALSE;
if (test)
{
....
}

Так как наша переменная test нигде явно не изменяется (то есть не стоит слева от оператора присваивания) то заботливый компилятор в результате оптимизации прочитает ее значение только один раз и больше не станет, переменная то на его взгляд нигде не изменяется! А эта переменная на самом деле может принять другое значение в результате выполнения другого потока, либо изменить свое значение неявно в прерывании. А это уже катастрофа! И для того, чтобы ее предотвратить как раз и используется спецификатор volatile. То есть объявить нашу переменную мы должны так:

volatile bool test = FALSE;

Продолжаем..
Спецификатор класса памяти extern.

Если программа состоит из нескольких файлов, как почти всегда и бывает, то без ключевого слова extern не обойтись ) Пусть в разных файлах используется одна и та же переменная x. Значит каждый файл должен знать о существовании этой переменной, но просто объявить переменную во всех файлах не прокатит — компилятор этого не допустит. Тут то и придет на помощь спецификатор extern. Вот пример: пусть программа состоит из двух файлов, в каждом из которых есть функции, использующий переменную x:

Файл номер 1

unsigned char x;
 
void main()
{
    x = 0x55;
    ...
    ...
}

Файл номер 2

extern unsigned char x;
 
void testFunction()
{
    x += 0x10;
}

При таком объявлении переменной ошибки не будет и все скомпилируется успешно.
Тут есть важный момент — а именно разница между понятиями определить и объявить переменную. При объявлении переменной ей присваивается определенный тип и значение, а при определении — для нее выделяется память. Таким образом, если перед именем переменной стоит спецификатор extern, то мы объявляем переменную, не определяя ее.

Вот собственно и все ) Получилась небольшая памятка, которая позволит сразу же и без проблем разобраться с этими ключевыми словами без путаницы.

Понравилась статья? Поделись с друзьями!

Спецификаторы const, volatile и extern.: 15 комментариев
  1. Не совсем поняла зачем «Спецификатор типа const.»
    const int maxNumOfBytes = 64;

    Если мы знаем что будем использовать константу,не проще сделать так:

    #define MAX_NUM_OF_BYTE 64 ?

    • Разницы нету, просто с const более правильно с точки зрения программирования, т.к. мы определяем тип переменной.

      • Переменная занимает место в оперативки (или в регистре). константа (сделланная дефайном) занимает место в флеш.

        • Я знаю, просто нам препод всегда говорил что это безопасно, конечно, под константы память в оперативки не забивается.
          Я сам дефайном пользуйюсь только там:
          #define count (int)5

          • Я не придираюсь,просто правила хорошего тона пишут что дефайны нужно писать так:
            #define СOUNT 5
            Переменние count или Count , тогда в тексте программы сразу видно где переменная, а где константа.

  2. День добрый, исправьте пожалуйста:
    1) const, volatile — квалификаторы типа
    2) extern — специфакатор типа (памяти)

    • По большому счету, все по разному называют (квалификатор — спецификатор). Я в этой статье, да и вообще, больше придерживаюсь терминологии, встречающейся в литературе

  3. Интересно было бы увидеть, можно ? Я думаю это не первоисточники, а «перевод».
    В стандарте 99-ого появился ещё и третий квалификатор restrict.

  4. Интересно было бы увидеть, можно ? Я думаю это не первоисточники, а «перевод».
    В стандарте 99-ого появился ещё и третий квалификатор restrict.
    Я не придираюсь, хороший ресурс мне понравился!
    Не знаю как вы я самоучка в программировании (не считая базового курса по паскалю, который уже и не помню) и то, что я читал по Си четко разделяло эти понятия.

    П.С. А можно ксати формат комментариев поменять ? Разрешение большое у монитора, но все равно больше трех слов в строку не входит 🙁

    • Навскидку помню, что у Герберта Шилдта было в книге по C++ так ) Возможно, даже прям дословно так =) Про ресурс, аналогично — захожу частенько на ZiBlog )
      С комментариями придумаю что-нибудь..

      • А, кстати, в оригинале я думаю как раз-таки qualifier и specifier используются как разные понятия..Так что замечание абсолютно верное )

  5. Разница между const и #define огромная
    Скорее static const ближе к #define, но есть важные отличия:
    1. У const задан тип — это значит у вас компилятор будет смотреть за соответствием типов
    2. Const учитывает namespace.
    3. Const используется при объявлении параметров функций. Не использовать const в этих случаях — отличие программиста от разработчика)

  6. Если говорить про С, то тогдав случае когда вам нужно, чтобы в программе можно было быстро изменить постоянное фиксированное значение на другое значение, то разумнее использовать define. Зачем в этом случае объявлять переменную, а потом делать её неизменяемой (использовать const) — только чтобы была возможность по тексту программы быстро заменить одно число на другое? Однозначно в этих целях define. Const же используется в современном мире в с++. Там объявление сложных типов как констант, позволяет предавать объекты сложных типов в функции без автоматического копирования по ссылке! без использования задолбавших всех указателей — для чистоты кода и т.д. и ещё много тонких приколюх, которые тут объяснять совсем неуместно — слишком сложная философия с++ 🙂

  7. Кстати, квалификатор extern — самый запутанный квалификатор!
    То и дело вижу в чужих программах, что extern прописывается где только можно и нельзя, внося дополнительную путаницу.
    Как я понял, extern, по правилам должен быть записан только в заголовочном файле .h, там где мы хотим использовать переменную из другого подключаемого файла. А вместо этого, его иногда записывают и в .с файле. Понятно, что это не сильно нарушает правила, но зачем так делают? По незнанию?

    Или несколько раз видел, что в .с файле определяют переменную и функцию с extern и ту же переменную и функцию объявляют в .h файле(!) И нигде в других файлах .c или .h эти переменные и функции больше не используют. Вот зачем так сделано?

    Или вот такой пример:
    В .с файле alarm.c определяют функцию и переменные

    extern uint8_t current_time;
    extern volatile uint8_t status;

    extern void init_alarms()
    {
    for(int =0;i<sizeof(alarm_param)*ALARM_NUM;i++)
    { *(((uint8_t*)Alarms)+i) = EEPROM_read(i); }
    }

    в .h файле alarm.h
    Объявляют функцию
    extern void init_alarms();

    В других файлах используются переменные current_time и status. Но зачем тогда было в .с файле alarm.c определять переменные с квалификатором extern?
    А функция init_alarms() и вовсе больше нигде не используется. Так зачем она определена с квалификатором extern и повторно объявлена то же с квалификатором extern?

    В общем, хорошо бы по больше примеров, как правильно работать с квалификатором extern.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *