Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Давыдов В.Г. - Программирование и основы алгоритмизации - 2003

.pdf
Скачиваний:
839
Добавлен:
13.08.2013
Размер:
9.55 Mб
Скачать

printf(

sizeof

( unsigned

long- )

) ;

(

float

)

) ;

 

"float

 

%d

\n",

sizeof

;

printf(

"double

double

%d

\n",

sizeof

(

double

)

)

print f (

"long

%d

\n",

sizeof

(

long

double

) ) ,

•retujETZi

0;

 

 

 

 

 

 

 

 

 

}

Tun void. Кроме перечисленных, к основным типам языка от­ носится тип void, но множество значений этого типа пусто. Он ис­ пользуется для определения функций, которые не возвращают зна­ чения, для указания пустого списка аргументов функции, как базо­ вый тип указателей и в операции приведения типов. Все это будет рассмотрено далее.

Взаключение приведем с использованием синтаксических диа­ грамм правила определения объектов в программах на языке Си/С++ (рис. 21). Следует заметить, что наряду с приведенными на этом рисунке разновидностями, есть и другие разновидности специ­ фикации типа и определяемого объекта, которые мы рассмотрим позже.

Вдополнение к имени и типу объекта существуют еще два ат­

рибута:

область действия;

время жизни объекта.

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

3.3.Класс хранения: область действия

ивремя жизни

Областью действия объекта (данного) называется та часть программы, в которой можно пользоваться этим объектом. В част­ ности, областью действия может быть:

блок операторов ( { . . . } );

модуль (файл);

вся программа в целом.

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

В языках Си/С++ область действия и время жизни объекта оп­ ределяются его классом хранения, в качестве которого можно ис­ пользовать следующие классы:

60

внешний;

внешний статический;

внутренний статический;

автоматический;

регистровый.

Список_опред._объектов *н Спецификация_типа —г-н Определяемый_объект

Специф._типа unsigned>

•( char У

и short У

и

long

У

 

 

 

•Г

float \

•Г

long

V ^

double >

Определяемый_объект

Идентификатор

Рис. 21. Правила определения объектов

3.4. Внешние и внешние статические данные

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

"внешнее объявление и определение данных".

61

Рассмотрим далее несложный иллюстрирующий пример.

Модуль (файл с объявлениями и определениями данных и операторами)

Объявления и определения внешних данных

Функция Внутренние определения данных

Операторы

Функция Внутренние определения данных

Операторы

Рис. 22. Обобш[ение определения модуля

Файл

Р2.СРР

одним

модулем

и

двумя функциями.

Программа яв­

Программа с

ляется

примером

и конкретизацией

информации,

представленной

на рис.

19

 

 

 

 

 

 

#include

<stdio.h>

//

Для

функций

ввода-вывода

//Прототип функции

void, save ( void. ) ;

//

Определение

внешних

данных: область действия -

программа,

//

время

жизни

-

программа

 

 

 

 

 

int

 

 

i l ,

±2;

 

 

 

 

 

 

 

//

Выполнение

программы

начинается

с

выполнения'

следующей

//

ниже

главной

 

функции

Возвращает

О при

успехе

 

int

main

(

void

)

 

 

//

 

{

save

(

) /

 

 

 

//

Вызов

функции:

определяет

И, i2

 

 

 

 

 

printf(

 

"\п

 

11

= %d 12

= %d"r

11,

12 )

;

 

 

 

re turn

0;

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

//

Определение,

функции,

задающей

значения

11,

12

 

void

save(

void

 

)

 

 

 

 

 

 

 

 

{

11 =

10; 12

=

15;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

return;

В этом примере определены внешние данные /1 и /2. Область действия внешних данных (в примере /1 и /2) распространяется на

62

весь модуль, а время их эюизни совпадает со временем

выполнения

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

В общем случае область действия внешних данных можно рас­ пространять и за пределы файла (модуля), используя служебное сло­ во extern {EXTERNal - внешний).

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

 

Файл

РЗ.СРР

программный

 

проект

с

двумя

 

функциями.

Пример

 

Двухфаиловый

 

 

 

иллюстрирует

область

действия

и

время

 

жизни

 

данных,

имеющих

внешний

класс

 

хранения.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

V

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

^include

 

<stdio.h>

 

 

//

Для

функций

 

 

ввода-вывода

 

 

//

Прототип

функции:

хотя

определение

 

этой

 

функции

находится

//

в

другом

файле

данного

 

программного

 

проекта

(SAVE.CPP),

//

в

данном

файле

прототип

также

нужен

-

он

 

используется

//

для

контроля

правильности

 

вызова

 

функции

 

 

 

 

 

void

save

( void.

) /

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//

Объявление

внешних

данных:

а

дополнительной

 

о

 

памяти

 

 

//

 

объявление

 

не

занимает,

 

лишь

говорит

 

том,

что

 

 

//

 

соответствующие

данные,

определены

 

в другом

файле

 

 

extern

 

Int

 

11,

12;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

int

main

( void

 

)

 

 

//

 

Возвращает

 

О при

 

успехе

 

 

{

save(

)

;

 

 

 

 

//

 

Вызов

 

функции:

 

определяет

11,

12

 

 

 

 

 

 

 

;

 

prlntf(

 

"\n

11

 

%d 12

= %d",

11,

12 )

 

 

 

 

 

 

 

return

 

0;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Файл

SAVE.CPP

программном

 

проекте,

 

главная

 

функция

 

кото-

 

Используется

 

в

 

 

 

 

\рого

имеется

в

 

файле

РЗ.СРР.

 

 

 

 

 

 

 

 

 

 

 

 

 

V

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// Прототип

функции:

в

принципе,

в

этом

файле

прототип

не

 

//

 

нужен,

так как

файл содержит

определение

 

 

этой

функции.

//

Мы оставляем

здесь

прототип

только

для

 

унификации

 

 

void

save

( void

 

) ;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//

Определение

 

внешних

данных:

занимает

память,

располагая

в

//

ней

соответствуюище

данные

 

 

 

 

 

 

 

 

 

 

 

63

±nt

ilr

±2;

-void

save ( void. )

 

il

10; ±2

15;

jretuim/

;

в приведенном примере внешние данные /1 и /2 определены в файле SAVE.CPP. Такое определение должно присутствовать толь­ ко в одном файле многофайлового программного проекта. Чтобы воспользоваться этими данными вне файла, где они определены (на­ пример, в файле РЗ.СРР), их следует объявить с использованием служебного слова extern. Таким образом, определение создает дан­ ное (см. файл SAVE.CPP), а объявление (см. файл РЗ.СРР)- только ссылается на данное, определенное в другом файле (рис. 23). Обра­ тите внимание, что объявление внешних данных, в отличие от их определения, может присутствовать в нескольких файлах программ­ ного проекта.

ОПРЕДЕЛЕНИЕ

Определить данное типа int

,Имя нового данного

 

 

int

11;

 

 

 

 

 

 

 

 

 

 

ОБЪЯВЛЕНИЕ

 

 

 

 

 

 

 

Указывает, что данное определено в

 

 

 

 

другом месте (в другом файле)

 

 

 

 

 

Указывает тип данного

 

 

 

 

 

Имя существующего данного

 

 

extern

int

i1;

 

 

 

 

 

 

 

 

Рис. 23. Определение и объявление внешних данных

 

В определении данного перед спецификацией его типа можно

использовать

служебное слово

static

(статический). При

этом

об­

ласть действия определяемого данного ограничивается только

тем

файлом,

где

данное определено,

а время

смсизни, как и ранее, совпа­

дает со временем

выполнения

программы.

 

 

 

 

Приведем и для этого случая иллюстрирующий пример.

 

_ _

 

 

 

 

 

 

 

 

 

 

Файл

Р4.СРР

программный

проект

с

двумя

функциями.

Пример

Двухфайловый

иллюстрирует

область действия

и

время

жизни

данных^

имеющих

внешний

и внешний

статический

классы

 

хранения

 

 

64

^include

 

<stdlo,h>

 

 

//

Для функций

 

 

ввода-вывода

 

//

Прототип

функции:

хотя

определение

этой

функции

находится

//

 

в

другом

 

файле

данного

программного

 

проекта

(SAVE1.СРР) ,

//

 

в данном

файле

прототип

также

нужен

-

он

 

используется

//

 

для

контроля

)

правильности

 

вызова

функции

 

 

 

void

savel

(

void.

;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//

Объявление

 

внешних

 

данных:

а

дополнительной

о

памяти

что

 

//

 

объявление

 

не

занимает,

лишь

говорит

том,

 

//

 

соответствующее

данные

определены

в

другом

файле

 

//

Gxtejcn

int

 

11;

 

 

 

Такое

объявление

 

 

ошибочно!

 

 

extejcn

int

 

 

12;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

int

 

main

( void

)

 

 

 

 

//

Возвращает

0

при

успехе

 

 

{

 

 

 

 

 

 

 

 

 

 

//

Вызов

функции:

 

 

определяет

 

 

 

savel(

)

;

 

 

 

 

 

 

 

 

 

 

 

 

 

%d",

//

 

значение

12

 

 

 

 

 

 

 

 

prlntf(

 

"\n

12

 

12

)

;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

return

0;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Файл

 

SAVE1.CPP

программном

 

проекте,

главная

функция

кото­

 

Используется

 

в

 

рого

имеется

в

файле

 

Р4.СРР

 

 

 

 

 

 

 

 

 

 

 

V

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// Прототип

функции:

в

принципе,

 

в

этом

файле

прототип

не

//

 

нужен,

так

как

файл

содержит

определение

 

этой

функции.

//

 

Мы оставляем

здесь

прототип

только

для

 

унификации

 

void

savel(

void

)

;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//

Определение

 

внешнего

и

внешнего

в

статического

 

данных:

данные

//

 

занимает

 

память,

 

располагая

 

ней

соответствуюш^^е

static

 

int

 

11;

 

 

 

//

Доступно

только

в

этом

файле

int

 

 

 

 

 

12;

 

 

 

//

Доступно

в

этом

файле

и

файле

 

 

 

 

 

 

 

 

 

 

 

//

 

Р4,СРР

 

 

 

 

 

 

 

void savel( void )

{

11 = 10; 12 = 15;

return;

}

Обратите внимание, что в этом примере в файле Р4.СРР объ­ явление

extern

int

11.

65

было бы ошибочным, так как областью действия /1 является только файл SAVE1.CPP.

Подводя итоги сказанному, выполним некоторые обобщения. В общем случае, программный проект является многофайловым. В рассуждениях, относящихся к объектам с описателем класса хране­ ния "внешний", будем считать, что программный проект содержит три файла (рис. 24 а).

 

Гипотетический программный проект

 

fl.cpp

f2.cpp

 

fS.cpp

1 m i l l ^ ^ ^ ^ ^ ^ И

 

 

 

 

1 o v f o r n

И - ^ ^ ^ H

 

1 extern int i1;

^ ^ H

 

 

 

{

 

 

 

float i1;

 

 

)

 

a)

H

Гипотетический программный проект

 

нfl.cpp

f2.cpp

 

fS.cpp

• " s t a t i c l ^ ^

 

1 ctatin

i9- ^ ^ ^ ^ H

 

 

 

1 static char ch;

^ H

 

 

 

{

 

 

 

char i2;

 

 

)

 

6)

Рис. 24. Внешние объекты:

a) с описателем класса хранения внешний;

б) с описателем класса хранения внешний статический

На этом рисунке область действия объекта /1 с описателем класса хранения extern содержит весь файл fl.cpp, часть файла f2.cpp и часть файла f3.cpp (выделена заливкой). Отметим, что на­ чальная часть файла f2.cpp не входит в область действия объекта /1 потому, что в этом файле объявление объекта /1 помещено в сере­ дину файла. Аналогично, в файле f3.cpp вложенный блок не входит

66

в область действия, так как в нем переопределяется объект с иден­ тификатором / 1 . Область действия объекта / 1 с описателем класса хранения extern можно сделать максимальной — все файлы про­ граммного проекта. Для этого достаточно объявление объекта /1 в файлах fZ.cpp и О.срр поместить в их начало, а вложенные блоки не должны содержать переопределение объекта /1 . Еще раз напомним,

что определение объекта

с

описателем класса

хранения

extern

долэюно быть только в одном

файле программного

проекта

(лю­

бом), а в остальных файлах

долэюно использоваться

только

объяв­

ление объекта.

 

 

 

 

Рис. 24 б иллюстрирует области действия объектов с описате­ лем класса хранения "внешний статический". Так, областью дейст­ вия объекта/является весь файл П.срр (и только он), областью дей­ ствия объекта ch является залитая часть файла f2.cpp, а областью действия объекта /2 является залитая часть файла О.срр.

Теперь можно сформулировать ряд важных уточнений, отно­ сящихся к областям действия и времени жизни объектов с описате­ лями класса хранения "внешний" и "внешний статический":

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

2. Областью

действия

внешнего

данного

в общем случае явля­

ется вся программа

за исключением влоэюенных блоков, в

которых

содерэюатся переопределения

данного

с тем

эюе именем.

Вложен­

ным блоком называется конструкция вида { ... }, в которой между фигурными скобками могут находиться определения данных и опе­ раторы.

3. Областью

действия

внешнего

статического

данного

явля­

ется файл,

где это

данное определено,

за исключением

влоэюенных в

этот файл

блоков,

в которых

содерэюатся переопределения

данного

с тем эюе

именем.

 

 

 

 

 

Обратите особое внимание на два последних уточнения' отно­ сительно областей действия внешних и внешних статических дан­ ных - это очень важно!

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

67

жизни этих данных познакомимся

подробнее с определениями, объ­

явлениями (прототипами) функций

и их вызовами.

3.5. Функции

Выше типы данных и области действия рассматривались при­ менительно только к объектам данных. В языках Си/С++ эти атри­ буты могут быть связаны и с функциями. Рассмотрим определения и объявления функций.

Общий вид определения функции представлен на рис. 25.

Класс: внешний (extern, по умолчанию) или статический (static).

Будем пользоваться умолчанием - опускать extern,

Тип возвращаемого значения (int - по умолчанию, void - отсутствует)

Имя функции

static extern

 

float power( int number, float exponent)

{

 

}

Имена параметров

 

Типы параметров

 

Рис. 25. Определение функции

Прежде всего, следует заметить, что функцию можно сделать статической, указав перед ее именем и типом слово static. В языках Си/С++, по умолчанию, все функции трактуются как внешние, если только перед типом функции не указано служебное слово static. Это означает, что областью действия внешней функции является вся программа. Определение функции как статической сужает область ее действия на оставшуюся часть файла, в котором она определена.

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

68

Объявление функции в языках Си/С++ называется

прототи­

пом функции. Вид его аналогичен

заголовку определения

функции,

за которым вместо блока функции

{ ... } следует символ ";". Другое

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

Давайте теперь рассмотрим иллюстрирующий пример — запи­ шем прототип, определение и пример вызова функции, определяю­ щей наибольшее и наименьшее значение из двух аргументов. При проектировании функции обычно вначале составляют специфика­ цию функции, которую можно рассматривать как графическую фор­ му записи прототипа функции. Спецификация (прототип) функции определяет ее интерфейсные свойства. Это означает, что на данном этапе функция рассматривается как "черный ящик" и определяются только ее интерфейсные свойства — входные и выходные данные. Спецификация функции для рассматриваемого примера представле­ на на рис. 26.

double Arg1

 

double &Max

double Arg1

MaxMin

double &Min

Исходные данные

Процесс

Результаты

(передаются по

 

(передаются по ссылке)

значению)

 

 

Рис. 26. Спецификация

функции

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

Файл

MAXMIN. СРР

 

 

проект с двумя

функциями.

Пример

Однофайловый

программный

иллюстрирует

работу

с

функцией:

объявление

(прототип)

функ­

ции^

определение

 

функции,

вызов

функции

без

возвращаемого

значения

и

оба

варианта

передачи

параметров

функции

-

по зна- \

чению

и

по

ссылке

 

 

 

 

 

 

 

V

 

 

 

 

 

 

 

 

 

 

 

^include

 

<stdlo.h>

 

//

Для

функций

ввода-вывода

 

//

Прототип

функции:

Argl,

Агд2, Мах,

//

В данном

случае

прототип функции

//

так как

вызов

функции

выполняется

//определена

void MaxMin ( double Argl, double Arg2,

М1п - параметры

функции

является

обязательным,

раньше,

чем

функция

double

&Max,

 

69