Обработка математики: 0%
 

printПеременные и типы

printОбъявление и инициализация переменных

Переменная в С соответствует некоторой ячейке в памяти или регистру процессора и хранит обрабатываемые данные. Перед использованием переменная должна определена или объявлена, т.е. программист должен сообщить компилятору тип переменной и её имя, чтобы компилятор назначил адрес и размер памяти для хранения переменной с указанным именем. Кроме типа программист определяет вид используемой памяти, ограничения на изменение, область видимости и время жизни переменной.

Общий вид оператора определения:

спецификаторы 

Пример:

int a, b;

Здесь определяются две переменные целого типа с именами a и b. При определении переменной можно указать начальное значение для неё после имени: "имя"="выражение". Пример:

int one=1, prime=1000000009;

Спецификатор const указывает, что значение переменной после определения нельзя изменить:

const double pi=3.141592653589793;

Данные для программы могут размещаться в регистровой, статической, стековой и динамической памяти. Отличия между этими видами памяти состоит в способе адресации и времени жизни данных.

Виды памяти

Вид памяти регистровая статическая стековая динамическая
Ограничения 4-32 значения ограничена размером памяти компьютера несколько мегабайт, можно изменить умолчание опциями при компиляции или компоновке ограничена размером памяти компьютера
Адресация прямая: номер регистра определяется компилятором абсолютная: адрес ячейки определяется на этапе компоновки и/или загрузки программы в память относительная: адрес ячейки вычисляется добавлением значения регистра SP к смещению, определяемому на этапе компиляции косвенная: память распределяется во время выполнения, адрес хранится в ячейках памяти других видов
Время жизни время нахождения данных в регистре определяется компилятором, при необходимости для данных используется стековая память в течении всего времени выполнения программы на время выполнения функции или блока операторов определяется программно
Определение внутри функции с помощью спецификатора register вне функций или внутри функции с помощью спецификатора static внутри функции или блока создание с помощью вызова функций malloc/calloc, уничтожение - free

Регистры

В Си с помощью спецификатора register можно указать, что некоторую часто используемую переменную следует разместить в регистре. Но данный описатель способа хранения можно считать устаревшим, так как, во-первых, оптимизирующие компиляторы эффективно используют регистры и могут размещать переменную в регистре только на время ее частого использования, а во-вторых, в современных процессорах реализовано многоуровневое кэширование, существенно уменьшающее время обращения к памяти.

Стек

Стек (stack - стопка) - это область памяти, в которую добавление и удаление данных происходит с одной стороны. При входе в некоторый блок программы данные добавляются в стек, при выходе из блока - удаляются. Данные, размещаемые в стеке, должны иметь фиксированный размер, так как смещение относительного адреса является константой и вычисляется во время компиляции.

Куча

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

Переменную можно использовать в её области видимости - от точки определения до конца блока или файла. Блок операторов в {} может содержать определение переменной с тем же именем, тогда новая переменная временно скрывает переменную, объявленную уровнем выше (см. пример).

Листинг 1 - Пример программы с использованием разных видов памяти

int a=1, b;
static int c=2;
int main()
{ int d, e=3;
  static int f=4;
  register int g=5;
  {
    int a=6, e=7;
  }
  int *h=malloc(sizeof(int));
  *h=6;
  free(h);
}

Размещение переменных в памяти

Рисунок 1 - Размещение переменных в памяти при выполнении программы

В скобках на рисунке указан адрес или регистр для переменной. Переменные a и b будут доступны в других модулях, видимость переменной c ограничена текущим модулем с помощью спецификатора static. Все статические переменные (a, b, c, f) существуют до начала выполнения программы, в том числе переменная f, определенная внутри функции (рисунок 1а). Если для статической переменной не указано начальное значение (b в примере), то она инициализируется нулем. Не инициализированные переменные в других видах памяти (d в примере) имеют неопределенное начальное значение (рисунок 1б). В строках 7-9 определяются переменные a и e (рисунок 1в), которые временно скрывают одноименные переменные и удаляются из стека при выходе из блока (рисунок 1г). Переменная h размещается на стеке и содержит адрес ячейки памяти в куче (рисунок 1д).

loading