Top.Mail.Ru

Использование спецификаторов 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, то мы объявляем переменную, не определяя ее.

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

Подписаться
Уведомить о
guest

15 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
Nemo
Nemo
10 лет назад

Не совсем поняла зачем "Спецификатор типа const."
const int maxNumOfBytes = 64;

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

#define MAX_NUM_OF_BYTE 64 ?

Леван
Леван
Ответ на комментарий  Nemo
10 лет назад

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

Nemo
Nemo
Ответ на комментарий  Леван
10 лет назад

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

Леван
Леван
Ответ на комментарий  Nemo
10 лет назад

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

Nemo
Nemo
Ответ на комментарий  Леван
10 лет назад

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

ZiB
ZiB
10 лет назад

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

ZiB
ZiB
10 лет назад

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

ZiB
ZiB
10 лет назад

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

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

Андрей
Андрей
9 лет назад

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

Дмитрий
Дмитрий
9 лет назад

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

Максим
Максим
9 лет назад

Кстати, квалификатор 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.

15
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x