С имеет 2 типа модификаторов, которые используются для контроля за способом доступа или модификации переменных. Эти модификаторы называются const и volatile.
Переменные типа const не могут изменяться операторами программы. Например:
const int a;
создаст целочисленную переменную, называемую а, которая не может быть модифицирована в программе. Она может использоваться в других типах выражений. Переменная с модификатором const получает своё значение или при инициализации, или каким-либо аппаратно-зависимым способом. Например, нижеприведённая строка присваивает count значение 100:
const int count = 100;
Помимо инициализации константа не может быть модифицирована программой.
Модификатор volatile используется для сообщения компилятору о возможности изменения значения способами, не определёнными в программе. Это важно, поскольку компилятор автоматически оптимизирует некоторые выражения, делая предположения, что содержимое переменных не изменяется в выражениях. Также некоторые виды оптимизации могут изменять порядок вычисления выражений во время процесса компиляции. Модификатор volatile предотвращает возникновение данных изменений.
Возможно использование этих модификаторов вместе. Например, если предполагается, что 0х30 является адресом порта, содержимое которого изменяется внешним устройством, то следующее объявление предохранит от побочных эффектов:
const volatile unsigned char *port = 0x30;
Спецификаторы хранения
Имеется 4 спецификатора хранения, поддерживаемые в С. Это
extern
static
register
auto
Они говорят компилятору, как должны храниться переменные. Спецификаторы предшествуют объявлению переменной. В общем случае это выглядит так:
спецификатор_хранения тип имя_переменной;
Поскольку С позволяет выполнять раздельную компиляцию модулей для большой программы, в целях ускорения компиляции и помощи управлению большими проектами, должны быть способы передачи информации о глобальных переменных файлам программы. Решение заключается в объявлении всех глобальных переменных в одном файле и использовании при объявлении в других файлах слова extern.
Файл 1
Файл 2
int x, y;
char ch;
int main(void)
{
…
}
void func1(void)
{
x = 23;
}
extern int x, y;
extern char ch;
void func22(void)
{
x = y/10;
}
void func23(void)
{
y = 10;
}
Имеется другой вариант использования extern. Когда используется глобальная переменная внутри функции, находящейся в том же файле, где происходит объявление глобальной переменной, то можно объявлять её как extern.
Статические переменные являются долговременными переменными, существующими на протяжении функции или файла. Они отличаются от глобальных переменных, поскольку не известны за пределами функции или файла, но могут хранить свои значения между вызовами.
Когда static применяется к локальной переменной, это приводит к тому, что компилятор создаёт долговременную область для хранения переменной почти таким же способом, как это делается для глобальной переменной. Ключевое различие между статической локальной и глобальной переменными заключается в том, что статическая локальная переменная остаётся известной только в том блоке, в котором она была объявлена.
Примером функции, требующей использования статических локальных переменных, является генератор последовательности чисел, создающий новое число, основываясь на старом.
int series(void)
{
static int series_num;
series_num = series_num+23;
return(series_num);
}
В данном примере переменная series_num существует между вызовами функций вместо того, чтобы каждый раз создаваться и уничтожаться как обычная локальная переменная. Это означает, что каждый вызов series( ) может создать новый член серии, основываясь на последнем члене без глобального объявления переменной.