Глобальная переменная — это переменная, объявленная вне
функции. Время её жизни совпадает со временем работы
программы. Этим глобальная переменная отличается и от локальной
(обычной) переменной функции, которая существует только до
окончания работы функции, так и от динамических переменных,
созданных вызовом типа malloc
, которые доступны до
вызова free
.
Глобальную переменную необходимо объявить. Использовать её можно как обычную переменную функции. Например,
int global_counter = 0; /* Объявление */
void process_new_request() {
global_counter += 1; /* увеличили счетчик запросов */
/*
** что-то делаем
*/
}
Важно! В функции не должно быть объявлено локальной ("обычной") переменной с тем же именем, что и глобальная переменная. Если это сделать, то локальная переменная "скроет" глобальную.
int global_counter = 0;
void process_unncounted_request() {
int global_counter = 120;
global_counter += 1; /* Изменяется значение ЛОКАЛЬНОЙ переменной! */
}
Следует учесть, что в такой ситуации компилятор не выдает
сообщений об ошибке или предупреждение.
Начальное значение глобальной переменной задаётся при её объявлении.
Глобальные переменные доступны по всех функциях, удовлетворяющих следующим условиям:
extern typename varname;
.
#include
, а значит доступны во всех функциях
файла.
Декларация нужна при раздельной компиляции. Например, в одном файле, пусть он называется process.c, реализована функция process_new_request, а в файле data.c объявлены переменные. Тогда файл process.c может выглядеть следующим образом.
extern int global_counter;
void process_new_request() {
global_counter += 1;
}
Декларация extern
аналогична прототипу функции и
означает, что где-то (в каком-то .с файле) будет объявлена
переменна типа int
с
именем global_counter.
Файл data.c может содержать одну строчку.
int global_counter = 0;
Если начальное значение глобальной переменной является числовой константой, или каким-то другим "простым" значением, то её объявление имеет простую форму. А можно в качестве начального значения использовать результат вычисления функции? Например, так:
#include <math.h>
double sin_at_one = sin(1.0);
Можно.
В какой момент происходит присвоение начального значения
переменной? До её первого использования. То есть функция, вызов
которой стоит в правой части объявления глобальной переменной,
может быть выполнена в любой момент между запуском программы и
первым обращением к глобальной переменной. Возможно, что функция
будет вызвана до начала main
!
Обязательно ли присваивать начальное значение при
объявлении? Нет. Но тогда нужно быть уверенным, что
переменной было присвоено значение до её первого
использования. Это можно сделать в функции main
, или
же написать специальную функцию init
, которая
вызывается в подходящий момент (да-да, в main).
Если необходимо, чтобы только несколько функций работали с глобальной переменной, а остальные части программы, реализованные в других файлах, не имели к ней доступа, то такая переменная может быть объявлена статической.
Рассмотрим такой пример.
#include <stdio.h>
static int global_counter;
void process_new_request() {
global_counter += 1;
}
void show_requests_statistics(FILE *stream) {
fprintf(stream, "We have processed %d requests so far!\n", global_counter);
}
При таком объявлении переменной global_counter её имя недоступно в
других модулях трансляции (хорошо-хорошо, это просто другие
файлы). Статические переменные, как и статические функции,
доступны только в том файле, в котором они объявлены и
реализованы.
Глобальные переменные могут быть удобны, но у них есть один существенный недостаток. Программы, которые используют глобальные переменные сложнее отлаживать, поскольку функции, которые используют глобальные переменные, перестают быть "замкнутыми". Часто возникают ситуации, когда ошибочное присвоение глобальной переменной значения в одной функции приводит к ошибке в другой функции, которая раньше считалась корректно работающей.
В языке Си можно объявить переменную, время жизни которой совпадает с временем выполнения программы, как у глобальных переменных, но доступ к ней есть только в одной функции. Такие переменные называются статическими переменными функции. Ограничимся примером.
#include <stdio.h>
void useless_function(FILE *stream) {
static int counter = 0;
fprintf(stream, "We have been called %d times!\n", ++counter);
}
При каждом новом вызове функции useless_function будет
выводится сообщение с количеством вызовов.
Важно! Если функция рекурсивная, то все её "копии" работают с одной переменной.