Шаг 53.
Внешние статические объекты (static)

    На этом шаге мы познакомимся с внешними статическими объектами.

    Областью действия статического внешнего объекта является модуль, в котором описан данный объект. При этом где-либо во внешних описаниях (т.е. вне определения функций) должно быть расположено определение внешнего статического объекта в виде:

    static  <спецификация_типа> <спецификация_данных>;

    На основании определения "под" объект отводится память и может быть произведена инициализация. Статические переменные можно инициализировать только константными выражениями и указателями на ранее описанные объекты.

    По умолчанию (если не задана инициализация) статические объекты получают нулевые начальные значения.

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


    Пример 1.
#include <iostream.h>
void main ()
{
  static int i;
  /* ---------------- */
  cout << "i = " << i << endl;
}
Текст этой программы можно взять здесь.

    Результат работы программы:

     i = 0

    При последующих входах в данную область статические переменные получают те значения, которые они имели при последнем выходе из области.

    По умолчанию все функции данного модуля, расположенные ниже определения статического объекта, включаются в его область действия - в них не обязательно дополнительно описывать объект для получения к нему доступа. Функции, определения которых расположены в модуле выше определения внешнего статического объекта, для получения доступа к нему должны содержать описание этого объекта с классом памяти extern.

    Константы являются объектами статического класса памяти.

    Функция может быть определена как статический внешний объект. В этом случае она будет доступной в любой точке данного модуля и не доступной за пределами модуля.

    Не объявляйте локальные переменные как static!


    Пример 2.
#include <iostream.h>
void main ()
{
      void trystat();
      /* -------------------------- */
      for (int count=1; count<=3; count++)
      {
         cout << "Итерация " << count << endl; trystat ();
      }
   }
/* ---------- */
void trystat ()
   {
      int fade=1;
      static int stay=1;
      cout << "fade = " << fade++ << " и stay = " << stay++ << endl;
   }
Текст этой программы можно взять здесь.

    Результат работы программы:

   Итерация 1:
   fade = 1 и stay = 1
   Итерация 2:
   fade = 1 и stay = 2
   Итерация 3:
   fade = 1 и stay = 3


    Если мы лишь немного видоизменим функцию trystat():
void trystat ()
   {
      int fade=1;
      int stay=1;
      cout << "fade = " << fade++ << " и stay = " << stay++ << endl;
   }
то получим следующий результат:
   Итерация 1:
   fade = 1 и stay = 1
   Итерация 2:
   fade = 1 и stay = 1
   Итерация 3:
   fade = 1 и stay = 1


    Пример 3. Что напечатает данная программа и почему?
#include <iostream.h>
int i=1;
void main ()
{
   auto int i,j;
   int reset(),next(int),last(int),nw(int);
   /* -------------------------- */
   i = reset();
   for (j=1; j<=3; j++)
    {
	cout << "i=" << i << ", j=" << j << endl; /* i=1,j=1     */
                                                /* i=1,j=2     */
                                                /* i=1,j=3     */
	cout << "next(i)=" << next(i) << endl;    /* next(i)=1   */
                                                /* next(i)=2   */
                                                /* next(i)=3   */
	cout << "last(i)=" << last(i) << endl;    /* last(i)=10  */
                                                /* last(i)=9   */
                                                /* last(i)=8   */
	cout << "nw(i+j)=" << nw(i+j) << endl;    /* nw(i+j)=12  */
                                                /* nw(i+j)=13  */
                                                /* nw(i+j)=14  */
    }
}
/* ---- */
int reset ()
{
 return i;
}
/* ---- */
int next (int j)
{
 return j=i++;
}
/* ---- */
int last (int j)
{
  static int i=10;
  return j=i--;
}
/* --- */
int nw (int i)
{
  auto int j=10;
  return i = j+=i;
}
Текст этой программы можно взять здесь.

    Результат работы программы:

   i=1, j=1
   next(i)=1
   last(i)=10
   nw(i+j)=12
   i=1, j=2
   next(i)=2
   last(i)=9
   nw(i+j)=13
   i=1, j=3
   next(i)=3
   last(i)=8
   nw(i+j)=14


    Пример 4. Что напечатает следующая программа?
/* Содержимое файла 53_4a.cpp */
#include <iostream.h>
int i=1;
int reset(), next(), last(), nw(int);
void main ()
{
      auto int i,j;
      i = reset ();
      for  (j=1; j<=3; j++)
      {
         cout << i << " " << j << " ";
         cout << next() << " ";
         cout << last() << " ";
         cout << nw(i+j) << endl;
      }
}
/* Содержимое файла 53_4b.cpp */
static int i=10;
int next ()
{
      return i+=1;
}
/* ------ */
int last()
{
      return i-=1;
}
/* ------ */
int nw(int i)
{
      static int j=5;
      return (i=j+=i);
}
/* Содержимое файла 53_4c.cpp */
int reset ()
{
      extern int i;
      return i;
}
Тексты этих файлов можно взять здесь: c53_4a.zip, c53_4b.zip, c53_4c.zip.

    Для запуска данной программы в системе BC++ 4.5 необходимо предварительно скомпилировать файлы c53_4b.cpp и c53_4c.cpp, используя командные строки:

   bcc32 -c c53_4b.cpp
   bcc32 -c c53_4c.cpp

    В результате получатся файлы c53_4b.obj и c53_4c.obj. Использование опции -c (Compile only) приводит к получению только OBJ-файла.

    Затем с помощью командной строки:

   bcc32 c53_4a.cpp c53_4b.obj c53_4c.obj
следует получить файл c53_4a.exe.

    Результаты работы программы:

   1 1 11 10 7
   1 2 11 10 10
   1 3 11 10 14

    Комментарии. В данной программе различные переменные имеют одинаковые имена, в комментариях мы будем отмечать разные переменные разными индексами, например: i0, i1 и т.д.

    int i = 1;        //i0 = 1;
    main ()
    {
       auto int i,j;
       i = reset (); //i1 = reset().
       extern int i; //Описание extern сообщает транслятору,  что i
                     //- внешняя переменная,  определенная где-то в
                     //другом месте, вероятно в другом файле. Здесь
                     //i относятся к i0.
    reset()
    {
      return i ; //i0 - внешняя переменная i, которая использу-
    }                  //ется в reset.
    for (j=1; j<=3;j++) //i1 = 1; j1 = 1;
    {
       cout << i << " " << j << " "; // i=i1, j=j1
       cout << next() << " ";
                     Вызов функции next()
    static int i=10; Второй файл программы начинается с определе-
                     ния внешней переменной i.  Кажется,  что это
                     определение вступает в конфликт с  описанием
                     внешней  переменной  в первом файле.  Однако
                     служебное слово static говорит  транслятору,
                     что эта переменная известна только в текущем
                     файле.  Другими словами, она доступна только
                     в функциях  next(),  last(),  new.  Мы будем
                     обозначать эту переменную как i2.
                     i2 = 10;
    int next()       В описании  функции next() нет никаких пара-
    {                метров. Переменная i2 = 11,  поэтому функция
       return (i+=1);next() возвращает 11. 
    }                          
       cout << last() << " ";
                     Вызов функции last()
    int last()
    {                Переменная i2 = 10,и last() возвращает 10. В
      return i-=1;   last()  используется то же i,  которое ранее
    }                было увеличено функцией next().
      cout << nw(i+j); //i=i1, j=j1
                      Вызов функции nw()
    nw (i)            //i=i3
       int i;         i3 = 2.
    {
     static int j=5;  j3 = 5;
     return(i=j+=2);  j3 = 7; i3 = 7;
                     Переменная i2 не   изменяется, i3  исчезает
                     после возврата, и j3 при новом обращении  к
                     nw() будет иметь значение 7.
    }
    for (j=1; j<=3; j++)  //j1 = 2.
    {                Опишем в общих чертах действие каждого  опе-
                     ратора в цикле.
      cout << i << " " << j << " "; // i=i1, j=j1
                     Выполнение тела цикла приводит к  увеличению
                     j1 на 1.
      cout << next() << " ";
                     Функция next()  увеличивает  i2 и возвращает
                     получившееся значение.
      cout << last() << " ";
                     Функция last() уменьшает i2 и возвращает по-
                     лучившееся значение.
      cout << nw(i+j) << endl;
                     Функция nw()  прибавляет свой параметр  к j3
                     и возвращает получившуюся сумму.
    }
}


    Следующий шаг будет посвящен классу памяти register.


Предыдущий шаг Содержание Следующий шаг