Рассмотрим следующий пример. Обратите внимание на то, что глобальные переменные first и last объявляются не перед, а после функции main().
#include <iostream>
using namespace std;
int main()
{
extern int first, last; // Использование глобальных переменных.
cout << first << " " << last << "\n";
return 0;
}
// Глобальное определение переменных first и last.
int first = 10, last = 20;
При выполнении этой программы на экран будут выведены числа 10 и 20, поскольку глобальные переменные first и last, используемые в инструкции cout, инициализируются этими значениями. Поскольку extern-объявление в функции main() сообщает компилятору о том, что переменные first и last объявляются где-то в другом месте (в данном случае ниже, но в том же файле), программу можно скомпилировать без ошибок, несмотря на то, что переменные first и last используются до их определения.
Важно понимать, что extern-объявления переменных, показанные в предыдущей программе, необходимы здесь только по той причине, что переменные first и last не были определены до их использования в функции main(). Если бы их определения компилятор обнаружил раньше определения функции main(), необходимости в extern-инструкции не было бы. Помните, если компилятор обнаруживает переменную, которая не была объявлена в текущем блоке, он проверяет, не совпадает ли она с какой-нибудь из переменных, объявленных внутри других включающих блоков. Если нет, компилятор просматривает ранее объявленные глобальные переменные. Если обнаруживается совпадение их имен, компилятор предполагает, что ссылка была именно на эту глобальную переменную. Спецификатор extern необходим только в том случае, если вы хотите использовать переменную, которая объявляется либо ниже в том же файле, либо в другом.
И еще. Несмотря на то что спецификатор extern объявляет, но не определяет переменную, существует одно исключение из этого правила. Если в extern-объявлении переменная инициализируется, то такое extern-объявление становится определением. Это очень важный момент, поскольку любой объект может иметь несколько объявлений, но только одно определение.
Переменные типа static — это переменные "долговременного" хранения, т.е. они хранят свои значения в пределах своей функции или файла. От глобальных они отличаются тем, что за рамками своей функции или файла они неизвестны. Поскольку спецификатор static по-разному определяет "судьбу" локальных и глобальных переменных, мы рассмотрим их в отдельности.
Локальная static-переменная поддерживает свое значение между вызовами функции.
Если к локальной переменной применен модификатор static, то для нее выделяется постоянная область памяти практически так же, как и для глобальной переменной. Это позволяет статической переменной поддерживать ее значение между вызовами функций.(Другими словами, в отличие от обычной локальной переменной, значение static-переменной не теряется при выходе из функции.) Ключевое различие между статической локальной и глобальной переменными состоит в том, что статическая локальная переменная известна только блоку, в котором она объявлена. Таким образом, статическую локальную переменную в некоторой степени можно назвать глобальной переменной, которая имеет ограниченную область видимости.
Чтобы объявить статическую переменную, достаточно предварить ее тип ключевым словом static. Например, при выполнении этой инструкции переменная count объявляется статической.
static int count;
Статической переменной можно присвоить некоторое начальное значение. Например, в этой инструкции переменной count присваивается начальное значение 200:
static int count = 200;