скачать рефераты
  RSS    

Меню

Быстрый поиск

скачать рефераты

скачать рефератыРеферат: Лекции по C++

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

              Еще одна специальная конструкция допускается в списке типов аргументов. Это фраза void *, которая специфицирует аргумент типа указатель. Эта фраза может быть использована в списке типов аргу­ментов вместо имени типа.

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

ся, то компилятор не проверяет соответствия между  формальными  и фактическими  параметрами при вызове функции. Более подробная ин­формация дана в разделе 7.4 "Вызовы функций".

               Тип возврата

               Функции могут возвращать величины любого типа за исключени­ем массивов и функций. Для этого посредством спецификатора  типа­"type-specifier" в об"явлении функции можно специфицировать любой тип:  основной,  структуру  или совмещение. Идентификатор функции может быть модифицирован одной или несколькими  звездочками  (*), чтобы об"явить возвращаемую величину типа указателя.

               Хотя функции и не допускают возвратов массивов или функций, но  они  могут возвращать указатели на массивы или функции. Функ­ции, которые возвращают указатели на  величины  типа  массив  или функция, об"являются посредством модификации идентификатора функ­ции  квадратными  скобками, звездочкой и круглыми скобками, чтобы сформировать составной декларатор. Формирование  и  интерпретация составных деклараторов рассматривались в разделе 4.3.2.

               Примеры:

               int add(int, int);                                                             /* Example 1 */

               double calc();                                                                 /* Example 2 */

               char *strfind(char *,...);                                                 /* Example 3 */

               void draf(void);                                                             /* Example 4 */

double (*sum(double, double)) [3];  /* Example 5 */ int (*select(void)) (int) ; /* Example 6 */

               char *p;                                                                          /* Example 7 */

               short *q;

               int prt(void *);

               В  первом  примере  об"является функция, поименованная add, которая требует два аргумента типа int и возвращает величину типа int.

               Во  втором примере об"является функция, поименованная calc, которая возвращает величину типа double. Список типов  аргументов не  задан.  В  третьем примере об"является функция, поименованная strfind, которая возвращает указатель на величину типа char. Фун­кция требует, по крайней мере один аргументуказатель на  величину типа char. Список типов аргументов заканчивается запятой с много­точием, обозначающим, что функция может потребовать большее число аргументов.

               В  четвертом  примере  об"является функция с типом возврата void (нет возвращаемой величины). Список типов  аргументов  также void, означающий отсутствие аргументов для этой функции.

               В  пятом  примере sum об"является как функция, возвращающая указатель на массив из трех величин типа double. Функция sum тре­бует два аргумента, каждый из  которых  является  величиной  типа double.

               В  шестом  примере функция, поименованная select, об"явлена без аргументов и возвращает указатель на функцию. Указатель возв­рата ссылается на функцию, требующую один  аргумент  типа  int  и возвращающую величину типа int.

               В  седьмом  примере  об"явлена функция prt, которая требует аргумент- указатель любого типа, и  которая  возвращает  величину типа  int. Любой указатель p или q могли бы быть использованы как аргументы функции без выдачи при этом предупреждающего сообщения.

     Классы памяти

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

Переменные с локальным временем жизни захватывают новую па-

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

ет свое значение.

               Хотя Си определяет два типа классов памяти, но, тем не  ме­нее, имеется следующих четыре спецификатора классов памяти:

               auto

               register

               static

               extern

               Об"екты классов auto и register имеют локальное время  жиз­ни. Спецификаторы static и extern определяют об"екты с глобальным временем  жизни. Каждый из спецификаторов класса памяти имеет оп­ределенный смысл, который влияет на видимость функций и  перемен­ных  в  той же мере, как и сами классы памяти. Термин "видимость" относится к той части программы, в которой могут  ссылаться  друг на друга функции и переменные. Об"екты с глобальным временем жиз­ни существуют на протяжении выполнения исходной программы, но они могут  быть  видимы не во всех частях программы. Видимость и свя­занная с ней концепция времени жизни рассмотрена в разделе 3.5.

Месторасположение об"явления переменной или функции  внутри

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

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

     Об"явления переменной на внешнем уровне

               Об"явления переменной на внешнем уровне используют специфи­каторы класса памяти static и extern или совсем опускают их. Спе­цификаторы класса памяти auto и register не допускаются на  внеш­нем уровне.

               Об"явления  переменных  на  внешнем уровне- это определения переменных или ссылки на определения, сделанные в другом месте.

Об"явление внешней переменной, которое  инициализирует  эту

переменную  (явно или неявно), называется определением этой пере­менной. Определение на внешнем уровне может задаваться в  следую­щих различных формах:

               -переменная  на  внешнем уровне может быть определена путем ее об"явления со спецификатором класса памяти static. Такая пере­менная может быть явно инициализирована  константным  выражением. Если  инициализатор отсутствует, то переменная автоматически ини­циализируется нулем во время компиляции. Таким образом,  об"явле­ния  static  int  k = 16; и static int k; оба рассматриваются как определения;

               -переменная определяется, когда она  явно  инициализируется

на  внешнем уровне. Например, int j = 3; это определение перемен­ной.

               Так как переменная определяется на внешнем уровне,  то  она видима  в пределах остатка исходного файла, от места, где она оп­ределена. Переменная не видима выше своего определения в  том  же самом  исходном файле ни в других исходных файлах программы, если не об"явлена ссылка, которая делает ее видимой.

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

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

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

               Переменная, на которую делается ссылка extern, должна  быть определена  на  внешнем уровне только один раз. Определение может быть сделано в любом из исходных файлов, составляющих программу.

Есть одно исключение из правил, описанных выше. Можно опус-

тить из об"явления  переменной  на  внешнем  уровне  спецификатор класса  памяти и инициализатор. Например, об"явление int n; будет правильным внешним об"явлением. Это об"явление имеет два  различ­ных смысла в зависимости от контекста.

               1.  Если где-нибудь в программе будет определена на внешнем уровне переменная с тем же именем, то об"явление является ссылкой на эту переменную, как если бы был использован спецификатор клас­са памяти extern в об"явлении.

               2.  Если  нет такого определения, то об"явленной переменной распределяется память во время линкования и переменная  инициали­зируется  нулем.  Если  в программе появится более чем одно такое об"явление, то память распределится для  наибольшего  размера  из об"явленных переменных. Например, если программа содержит два не­инициализированных  об"явления переменной i на внешнем уровне int i; и char i; то память во время линкования распределится под  пе­ременную i типа int.

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

               Пример:

                 /*****************************************************

                                                SOURCE FILE ONE *****************************************************/

                 extern int i;                                        /* reference to i

                                                                                                defined below */

                 main()

                 {

                                    i++;

                                    printf("%d\n", i);    /* i equals 4 */

                                    next();

                 }

                 int i = 3;                    /* definition of i */

                 next()

                 {

                                    i++;

                                    printf("%d\n", i);    /* i equals 5 */

                                    other();

                 }

/***************************************************** SOURCE FILE TWO

                 *****************************************************/

                 extern int i;               /* reference to i in

                                                                                                first source file */

                 other()

                 {

                                    i++;

                                    printf("%d\n", i);    /* i equals 6 */

                 }

               Два исходных файла  в  совокупности  содержат  три  внешних об"явления  i. Одно об"явление содержит инициализацию- int i = 3; , где глобальная переменная i определена  с  начальным  значением равным 3.

               Самое  первое  об"явление extern в первом файле делает гло­бальную переменную видимой выше ее определения в файле.

               Без об"явления extern функция main не смогла  бы  сослаться на  глобальную  переменную  i.  Об"явление extern переменной i во втором исходном файле делает глобальную переменную видимой в этом исходном файле.

               Все три функции выполняют одну и ту же задачу: они увеличи­вают i на 1 и печатают  получившееся  значение.  (Предполагается, что функция printf определена где-то еще в программе.). Печатают­ся величины равные 4, 5 и 6.

               Если бы переменная i не была бы инициализирована,она бы бы­ла  автоматически  установлена  в 0 при линковании. В этом случае напечатанные значения были бы равны 1, 2 и 3.

Об"явление переменной на внутреннем уровне

               Любой из четырех спецификаторов класса  памяти  может  быть использован  для об"явления переменной на внутреннем уровне. Если спецификатор класса памяти опускается в об"явлении переменной  на внутреннем уровне, то подразумевается класс памяти auto.

Спецификатор  класса памяти auto об"являет переменную с ло-

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

               Спецификатор  класса памяти register сообщает компилятору о том, чтобы он распределил память под переменную в регистре,  если это  возможно. Использование регистровой памяти обычно приводит к более быстрому времени доступа и к меньшему размеру  результирую­щего кода. Переменные, об"явленные с классом памяти register име-

ют ту же самую видимость, что и переменные auto.

               Число регистров, которое может быть использовано под память переменных,  зависит от машины. Когда компилятор встречает специ­фикатор класса памяти register в об"явлении, а свободного регист­ра не имеется, то для  переменной  распределяется  память  класса auto.  Компилятор  назначает  переменным регистровую память в том порядке, в котором появляются об"явления в исходном файле. Регис­тровая память, если она имеется, гарантирована только для  целого и адресного типов.

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

               Переменные класса памяти static могут быть инициализированы константным выражением. Если явной инициализации нет, то перемен­ная  класса памяти static автоматически устанавливается в 0. Ини­циализация выполняется один раз во время компиляции.  Инициализа­ция переменной класса памяти static не повторяется при новом вхо­де в блок.

               Переменная,  об"явленная  со  спецификатором  класса памяти extern, является ссылкой на переменную с тем же самым именем, оп­ределенную на внешнем уровне в любом исходном файле программы.

Цель внутреннего об"явления extern  состоит  в  том,  чтобы

сделать  определение  переменной  внешнего  уровня видимой внутри блока. Внутреннее об'явление extern не  изменяет  видимость  гло­бальной переменной в любой другой части программы.

               Пример:

               int i = 1;

               main()

                 {                 /* reference to i, defined above */

                                    extern int i;

/* initial value is zero; a is

visible only within main */

                                    static int a;

/* b is stored in a register, if possible */ register int b = 0;

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17


Новости

Быстрый поиск

Группа вКонтакте: новости

Пока нет

Новости в Twitter и Facebook

  скачать рефераты              скачать рефераты

Новости

скачать рефераты

© 2010.