Давно уже собирался и вот решил сделать небольшую шпаргалку по основным спецификаторам, к помощи которых можно и нужно прибегать при программировании. Без лишних слов, сразу же, переходим к сути.
Квалификатор типа 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."
const int maxNumOfBytes = 64;
Если мы знаем что будем использовать константу,не проще сделать так:
#define MAX_NUM_OF_BYTE 64 ?
Ну да, я на С всегда определяю дефайном
Разницы нету, просто с const более правильно с точки зрения программирования, т.к. мы определяем тип переменной.
Переменная занимает место в оперативки (или в регистре). константа (сделланная дефайном) занимает место в флеш.
Я знаю, просто нам препод всегда говорил что это безопасно, конечно, под константы память в оперативки не забивается.
Я сам дефайном пользуйюсь только там:
#define count (int)5
Я не придираюсь,просто правила хорошего тона пишут что дефайны нужно писать так:
#define СOUNT 5
Переменние count или Count , тогда в тексте программы сразу видно где переменная, а где константа.
День добрый, исправьте пожалуйста:
1) const, volatile - квалификаторы типа
2) extern - специфакатор типа (памяти)
По большому счету, все по разному называют (квалификатор - спецификатор). Я в этой статье, да и вообще, больше придерживаюсь терминологии, встречающейся в литературе
Интересно было бы увидеть, можно ? Я думаю это не первоисточники, а "перевод".
В стандарте 99-ого появился ещё и третий квалификатор restrict.
Интересно было бы увидеть, можно ? Я думаю это не первоисточники, а «перевод».
В стандарте 99-ого появился ещё и третий квалификатор restrict.
Я не придираюсь, хороший ресурс мне понравился!
Не знаю как вы я самоучка в программировании (не считая базового курса по паскалю, который уже и не помню) и то, что я читал по Си четко разделяло эти понятия.
П.С. А можно ксати формат комментариев поменять ? Разрешение большое у монитора, но все равно больше трех слов в строку не входит 🙁
Навскидку помню, что у Герберта Шилдта было в книге по C++ так ) Возможно, даже прям дословно так =) Про ресурс, аналогично - захожу частенько на ZiBlog )
С комментариями придумаю что-нибудь..
А, кстати, в оригинале я думаю как раз-таки qualifier и specifier используются как разные понятия..Так что замечание абсолютно верное )
Разница между const и #define огромная
Скорее static const ближе к #define, но есть важные отличия:
1. У const задан тип - это значит у вас компилятор будет смотреть за соответствием типов
2. Const учитывает namespace.
3. Const используется при объявлении параметров функций. Не использовать const в этих случаях - отличие программиста от разработчика)
Если говорить про С, то тогдав случае когда вам нужно, чтобы в программе можно было быстро изменить постоянное фиксированное значение на другое значение, то разумнее использовать define. Зачем в этом случае объявлять переменную, а потом делать её неизменяемой (использовать const) - только чтобы была возможность по тексту программы быстро заменить одно число на другое? Однозначно в этих целях define. Const же используется в современном мире в с++. Там объявление сложных типов как констант, позволяет предавать объекты сложных типов в функции без автоматического копирования по ссылке! без использования задолбавших всех указателей - для чистоты кода и т.д. и ещё много тонких приколюх, которые тут объяснять совсем неуместно - слишком сложная философия с++ 🙂
Кстати, квалификатор 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.