Содержание

классы хранения

В Си существует четыре основных класса хранения: auto, extern, static, register.

auto

Класс хранения auto является классом по умолчанию для всех локальных1) переменных.

void myFunction() {
  int a; // То же самое, что и "auto int a;""
  a = 10;
  // a доступна только внутри myFunction
}

extern

Используется для объявления глобальной переменной или функции, которая определена в другом файле.

// main.c
#include <stdio.h>
 
char message[] = "Hello";
 
void print() {
  printf("Hello from extern function\n");
}
int sum(int x, int y) {
  return x + y;
}
//app.c
#include <stdio.h>
 
extern char message[]; // переменная message из файла main.c
void print(void); // функция print из main.c
int sum(int, int); // функция sum из main.c
 
int main(void){
  // выводим на консоль внешнюю переменную message
  printf("%s \n", message);
 
  // вызываем внешнюю функцию print
  print();
 
  // вызываем другую внешнюю функцию - sum
  printf("4 + 5 = %d \n", sum(5, 4));
 
  return 0;
}

static

Ключевое слово static имеет два основных применения в зависимости от контекста: для локальных переменных и для глобальных переменных/функций.

Когда static применяется к локальной переменной, он изменяет ее жизненный цикл, сохраняя ее значение между вызовами функции. Основные характеристики:

Когда static применяется к глобальной переменной или функции, он ограничивает их область видимости текущим файлом. Это означает, что к такой переменной или функции нельзя будет обратиться из другого файла с помощью extern. В этом случае действуют следующие характеристики:

register

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

Однако в современных компиляторах register почти не используется, так как они самостоятельно выполняют очень сложную оптимизацию и часто лучше программиста решают, какие переменные стоит помещать в регистры.
К register-переменной нельзя применить оператор взятия адреса &, так как у нее нет адреса в памяти.
1)
Это означает, что если вы объявляете переменную внутри функции или блока без указания класса хранения, она автоматически принимает тип хранения auto.