Переменные в C: объявление, определение, инициализация, область видимости и классы хранения
Что такое переменная?
Переменная — именованная область памяти, которая хранит значение определённого типа. Имя переменной — это идентификатор, связанный с адресом в памяти.
Объявление vs Определение
- Объявление (declaration) — сообщает компилятору: «существует переменная такого типа с таким именем». Не выделяет память (кроме
externбез инициализации). - Определение (definition) — выделяет память, возможно инициализирует. В C определение — это тоже объявление.
extern int a; // только объявление (нет памяти)
int b; // определение (память выделена, значение неопределено)
int c = 42; // определение с инициализацией
static int d = 10; // определение с внутренней линковкой
Базовые типы переменных
| Тип | Описание | Размер (тип.) |
|---|---|---|
char | 1 байт, целое / символ | 1 |
int | Целое «естественного» размера | 4 |
float | Одинарная точность | 4 |
double | Двойная точность | 8 |
void | Отсутствие типа (только для указателей/функций) | — |
Также: short, long, long long, signed/unsigned модификаторы, _Bool (C99), stdint.h типы.
Инициализация
int a = 10; // копирующая инициализация
int b(20); // ошибка в C! Это C++ синтаксис
int c = {30}; // список инициализации (C99, для структур/массивов)
int d = 10, e = 20; // несколько в одном объявлении
const int LIMIT = 100;// константа (read-only)
Автоматическая инициализация
| Класс хранения / область | Начальное значение |
|---|---|
Глобальные / static (файл или функция) | Нулевое: 0, 0.0, NULL, '\0' |
| Локальные (auto, register) | Неинициализированы — мусор в памяти (UB при чтении) |
Динамические (malloc) | Неинициализированы (мусор) |
calloc, calloc | Обнулены |
Правило: всегда инициализируйте локальные переменные при объявлении.
Область видимости (Scope) и время жизни (Lifetime)
| Тип переменной | Область видимости | Время жизни | Пример |
|---|---|---|---|
| Локальная (auto) | Блок {...} где объявлена | Вход в блок → выход из блока | void f() { int x; } |
| Глобальная (file scope) | Весь файл после объявления (все функции) | Запуск программы → завершение | int g; void f() {} |
| Static локальная | Блок, где объявлена | Запуск → завершение программы | void f() { static int x; } |
| Static глобальная | Только этот файл (внутренняя линковка) | Запуск → завершение | static int g; |
| Extern глобальная | Вся программа (внешняя линковка) | Запуск → завершение | extern int g; в другом файле |
| Параметры функции | Тело функции | Вход в функцию → выход | void f(int x) |
Классы хранения (Storage Classes)
| Класс | Ключевое слово | Область | Жизнь | Линковка | Инициализация по умолчанию |
|---|---|---|---|---|---|
| Автоматический | auto (по умолчанию) | Блок | Блок | Нет | Мусор |
| Регистровый | register | Блок | Блок | Нет | Мусор |
| Статический (локальный) | static | Блок | Программа | Нет | 0 |
| Статический (глобальный) | static | Файл | Программа | Внутренняя | 0 |
| Внешний | extern | Программа | Программа | Внешняя | 0 (если определение) |
auto
Явное указание автоматического класса хранения. В современном C используется редко (подразумевается по умолчанию для локальных переменных). Не путать с C++11 auto (вывод типа)!
register
Подсказка компилятору: «храни в регистре процессора». Нельзя взять адрес (&var — ошибка). Современные компиляторы сами лучше решают, что положить в регистры. Используется редко.
static (локальный)
Сохраняет значение между вызовами функции:
void counter() {
static int count = 0; // инициализируется ОДИН раз
count++;
printf("%d\n", count);
}
counter(); // 1
counter(); // 2
counter(); // 3
static (глобальный)
Ограничивает видимость файлом (internal linkage). Предотвращает конфликты имен при линковке.
extern
Объявление переменной, определённой в другом файле:
// file1.c
int global_counter = 0; // определение
// file2.c
extern int global_counter; // объявление
void use_it() { global_counter++; }
Компиляция: gcc file1.c file2.c -o prog.
Lvalues и Rvalues
- lvalue (locator value) — выражение, ссылающееся на объект в памяти (имеет адрес). Может стоять слева от
=. Примеры: переменная, разыменование указателя*ptr, элемент массиваarr[i]. - rvalue (read value) — временное значение, не имеющее адреса. Только справа от
=. Примеры: литералы42,3.14, результаты выраженийa + b, возвращаемые значения функций (кроме ссылок в C++).
int x = 10; // x — lvalue, 10 — rvalue
x = 20; // OK
10 = 20; // ОШИБКА: 10 — rvalue, нельзя присваивать
int *p = &x; // &x требует lvalue
*p = 30; // *p — lvalue
Пример: демонстрация областей видимости
#include <stdio.h>
int global = 100; // глобальная, внешняя линковка
static int file_static = 200; // глобальная, внутренняя линковка
void func(int param) { // param — формальный параметр
int local = 10; // локальная (auto)
static int static_local = 0; // статическая локальная
printf("global=%d, file_static=%d, param=%d, local=%d, static_local=%d\n",
global, file_static, param, local, static_local);
static_local++;
local = 999; // изменится только в этом вызове
}
int main() {
func(1);
func(2);
func(3);
// local сбрасывается каждый вызов, static_local накапливает
return 0;
}
Язык C
- Мастерство C# переменных и примитивных типов данных: полное руководство
- Область видимости переменных в C#: класс, метод и блок
- Освоение переменных, литералов и констант в C++: подробное руководство
- Переменные, константы и литералы в C: полное руководство
- Классы хранения в C: область видимости, время жизни и производительность
- Ключевое слово global в Python: как и когда использовать
- Переменные и литералы в Java: подробное руководство
- Переменные и типы данных в C++: подробное руководство по int, double, char, string, bool
- Понимание назначений в Verilog: типы, синтаксис и лучшие практики
- Типы переменных в Java: локальные, экземпляра и статические