Файл: Pobegaylo_A._C_Cplus_dlya_studenta.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 13.12.2020

Просмотров: 4253

Скачиваний: 28

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Глава 7. Структура программы на языке С 

91 

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

7.3. Связывание идентификаторов 

Программа на языке программирования С состоит из одного или 
нескольких исходных файлов, которые содержат код программы. 
Эти  файлы  также  называются 

единицами  компиляции

,  т. к.  каж-

дый из них является исходным данным для компилятора. Резуль-
татом  компиляции  исходного  файла  является  объектный  файл, 
который представляет собой программу в кодах микропроцессо-
ра, эквивалентную по смыслу исходной программе на языке про-
граммирования С. Если программа на языке программирования С 
состоит из нескольких исходных файлов, то в результате ее ком-
пиляции получается такое же количество объектных файлов. Все 
эти  объектные  файлы  нужно  собрать  в  один  исполняемый  мо-
дуль. Эту задачу решает редактор связей (linker), который также 
называется компоновщиком. 
При  разработке  программы,  состоящей  из  нескольких  исходных 
файлов, может возникнуть следующая проблема. В одном исход-
ном  файле  нужно  сослаться  на  идентификатор  переменной  или 
функции, которая определена в другом исходном файле. Для ре-
шения этой проблемы между одинаковыми идентификаторами в 
разных  исходных  файлах  программы  устанавливается  связь,  ко-
торая называется 

связыванием 

или  

сцеплением 

(linkage)

 перемен-

ных

. Связывание реализуется при помощи назначения идентифи-

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


background image

Часть I. Язык программирования С 

92 

 

внутреннее  связывание,  т. е.  на  идентификатор  можно  ссы-
латься только внутри исходного файла, в котором он опреде-
лен; 

 

внешнее связывание, т. е. на идентификатор можно ссылаться 
как внутри исходного файла, в котором он определен, так и в 
других исходных файлах; 

 

отсутствие  связывания,  т. е.  на  идентификатор  можно  ссы-
латься только внутри блока, в котором он определен. 

Глобальные переменные и функции имеют внешнее связывание, 
т. е. на них можно ссылаться в других исходных файлах. Локаль-
ные переменные не имеют связывания. 
Так  как  глобальная  переменная  имеет  внешнее  связывание,  то 
глобальная  переменная  с  одним  и  тем  же  именем  может  быть 
объявлена  в  программе  только  один  раз.  Если  глобальные  пере-
менные  с  одним  именем  будут  объявлены  в  разных  исходных 
файлах  программы,  то  компилятор  эти  объявления  пропустит,  а 
компоновщик выдаст ошибку, указывающую на повторение име-
ни переменной. 
В связи с введением понятия связывания идентификаторов нужно 
различать объявление и определение переменной. Если объявле-
ние  переменной  вызывает  распределение  памяти  для  этой  пере-
менной, то такое объявление называется 

определением переменной

7.4. Спецификаторы классов памяти 

В языке программирования C для  управления временем сущест-
вования  переменных  и  связыванием  идентификаторов  использу-
ются  специальные  ключевые  слова,  которые  называются 

специ-

фикаторами  классов  памяти

.  Отметим,  что  спецификаторы 

классов памяти не изменяют области видимости идентификатора. 
Существуют четыре спецификатора классов памяти: 

extern

auto

static

 и 

register

. Используются спецификаторы классов памяти 

при  объявлении  переменных  и  функций  и  записываются  перед 
идентификатором  или  спецификатором  типа  переменной  или 
функции. 


background image

Глава 7. Структура программы на языке С 

93 

Спецификатор 

extern

 

Спецификатор 

extern

 управляет связыванием идентификаторов и 

указывает  компилятору, что  переменная  или функция  уже  опре-
делена  вне  области  видимости  своего  объявления  в  том  же  или 
другом исходном файле. 
Если спецификатор 

extern

 используется при объявлении локаль-

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

Листинг 7.2. Использование спецификатора 

extern

  

с локальной переменной 

#include <stdio.h> 
int n = 1; 
int main(void) 

  int n = 2; 
  { 
    extern int n; 
    printf("n = %d\n", n); /* печатает n = 1 */ 
  } 
  return 0; 

Если  спецификатор 

extern

  используется  с  глобальной  перемен-

ной, то это указывает компилятору, что эта переменная ссылается 
на глобальную переменную с тем же именем, но которая опреде-
лена  в  другом  исходном  файле.  Этот  случай  рассмотрен  в  лис-
тингах 7.3 и 7.4, которые описывают исходные файлы, принадле-
жащие одной программе. 

Листинг 7.3. Исходный файл  с определением  
глобальной переменной и прототипом функции 

#include <stdio.h> 
int n; 


background image

Часть I. Язык программирования С 

94 

void foo(void); 
int main(void) 

  foo(); 
  printf("n = %d\n", n); /* печатает n = 1 */ 
 
  return 0; 

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

extern int n; 
void foo(void) { ++n; } 

Спецификатор 

extern

  также  может  использоваться  при  объявле-

нии  функции.  Это  указывает  компилятору,  что  функция  опреде-
лена  в  другом  исходном  файле.  Однако  объявление  функции 
имеет этот спецификатор по умолчанию и поэтому он редко ис-
пользуется  в  этом  случае.  В  листинге  7.4  определена  функция 

foo

,  которая  вызывается  в  листинге  7.3.  Поэтому  в  листинге  7.3 

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

Спецификатор 

auto

 

Спецификатор 

auto

  управляет  временем  существования  локаль-

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

Спецификатор 

static

 

Спецификатор 

static

  управляет  временем  существования  ло-

кальных  переменных  и  связыванием  идентификаторов  глобаль-
ных переменных и функций. 
Если  локальная  переменная  определена  со  спецификатором 

static

,  то  она  существует  в  течение  всего  времени  исполнения 

программы.  Если  такая  переменная  не  инициализируется  при 


background image

Глава 7. Структура программы на языке С 

95 

своем определении, то компилятор устанавливает начальное зна-
чение этой переменной в ноль. 
В листинге 7.5 приведена программа, в которой показано как из-
меняется значение статической локальной переменной. 

Листинг 7.5. Изменение значения статической локальной  
переменной 

#include  <stdio.h> 
int count(void) 

  static int c; 
 
  return ++c; 

int main(void) 

  count(); 
  printf("count = %d\n", count());  /* печатает count = 2 */ 
 
  return 0; 

Для  глобальной  переменной  или  функции  спецификатор 

static

 

ограничивает ее связывание только исходным файлом, в котором 
эта переменная или функция определена. То есть к этой перемен-
ной или функции нельзя обратиться из другого исходного файла. 
Например,  если  в  листингах  7.3  и  7.4  добавить  спецификатор 

static

 в определения глобальной переменной 

n

 и функции 

foo

, то 

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

Спецификатор 

register

 

Спецификатор 

register

  указывает  компилятору,  что  значение 

переменной  нужно  хранить  в  регистре  микропроцессора.  Этот 
спецификатор  может  применяться  только  к  локальным  перемен-
ным  и  параметрам  функций.  Компилятор  не  обязан  исполнять 
требования  спецификатора 

register

  и  может  хранить  значения 


Смотрите также файлы