46019 (665326), страница 8
Текст из файла (страница 8)
5. Если во взятом в фигурные скобки списке инициализаторов меньше, чем элементов структуры, то оставшаяся часть структуры неявно инициализируется таким же образом, как и объекты со статической продолжительностью существования в памяти.
Скалярные типы инициализируются в одномвыражении, которое опционально можно заключить в фигурные скобки. Исходное значение объекта берется из выражения; действуют те же ограничения на тип и выполняемые преобразования, что и для простых присваиваний.
Для объединений заключенный в фигурные скобки инициализатор инициализирует компонент, появляющийся в списке объявления объединения первым. Для структур и объединений с автоматическим размещением в памяти инициализатор должен быть одним из:
- списком инициализаторов, как описано в следующем разделе
- отдельным выражением с типом, совместимым с объединением или структурой. В этом случае исходное значение объекта берется из выражения.
Массивы, структуры и объединения
Вы инициализируете массивы и структуры (если хотите, то во время объявления) при помощи заключенного в фигурные скобки списка инициализаторов для компонентов илиэлементов рассматриваемого объекта. Инициализаторы даются по возрастанию индекса массивов или номеров компонентов. Инициализация объединенийвыполняется заключенным в фигурные скобки инициализатором для первого компонента объединения. Например, вы можете объявить массив days, предназначенный для подсчета того, сколько раз каждый день недели был в том или ином месяце (предполагая, что каждый день недели был в месяце хотя бы один раз), следующим образом:
int days[7] = (* 1, 1, 1, 1, 1, 1, 1)
Этими правилами можновоспользоваться для инициализации символьных массивов и широких символьных массивов:
1. Можно инициализировать массивы символьного типа с помощью строки литералов, опционально заключенной в фигурные скобки. Каждый символ строки, включая нулевой терминатор, инициализирует последовательно расположенные элементы массива. Например, вы могли объявить:
char name[] = (* "Unknown" *);
установив тем самым массив из восьми элементов, элементы которого равны 'U'(для name[0]), 'n' (для name[1]), и т.д. (включая нулевой терминатор.)
2. Вы можете инициализировать широкий символьный массив (то есть совместимый с wchar_t), используя широкий строковый литерал, опционально заключенный в фигурные скобки. Как и в случае символьных массивов, коды широкого символьного литерала последовательно инициализируют элементы массива.
Ниже приводится пример инициализации структуры:
struct mystruct (*
int i;
char str[21];
double d;
*) s = (* 20, "Borland", 3.14 *);
Сложные компоненты структуры,такиекак массивыили структуры, могутбытьинициализированы соответствующими выражениями во вложенных фигурных скобок. Можно убрать фигурные скобки, но тогда приходится выполнять дополнительные правила, и такая практика не рекомендуется.
Простые объявления
Простые объявления идентификаторов переменных имеют следующий шаблон:
тип-данных перем1 , перем2 ,...;
где перем1, перем2, ... это произвольная последовательность отдельных идентификаторов с опциональными инициализаторами. Каждая из переменных объявляется с указанным типом-данных. Например,
int x = 1, y = 2;
создает две целочисленных переменных x и y (и инициализирует их значениями 1 и 2, соответственно).
Это былиобъявления определения; при этом распределялась память и выполнялась инициализация.
Инициализатор для динамического локального объекта может представлять собой любое выражение, дающее при вычислении совместимое с типом участвующейв присваивании переменной значение. Инициализаторы для статических объектов должны являться константами или выражениями с константами.
В C++ инициализатор статического объекта может являться любым выражением, включающим в себя константы и ранее определенные переменные и функции.
Спецификаторы класса памяти
Спецификатор класса памяти,или спецификатор типа, обязательно должен присутствовать в объявлении. Спецификатор класса памяти может быть одним из следующих ключевых слов:
auto register typedef
extern static
Использование спецификатора класса памяти auto
Спецификатор класса памяти auto используется только в объявлениях переменных с локальным контекстом. Он подразумевает локальную (автоматически определяемую) продолжительность, но поскольку это есть умолчание для всех объявлений переменных локального контекста, то использование его редко.
Использование спецификатора класса памяти extern
Спецификатор класса памяти extern может быть использован в объявлениях функций и переменных с контекстом файла и с локальным контекстом для обозначения внешнего типа компоновки. В случае переменных сконтекстом файла спецификатор класса памяти extern является умолчанием.При использовании спеременными extern указывает на то,что данная переменная имеетстатическую продолжительность. (Помните, что функции всегда имеютстатическую продолжительность).
Использование спецификатора класса памяти register
Спецификатор класса памяти registerдопустим только в объявлениях локальных переменных и параметров функций. Он эквивалентен класса auto, за исключением того, что компилятору в данном случае делается запрос о размещении при возможности данной переменной в регистре. Распределение для переменной регистра может значительно уменьшить размер программы и увеличить скорость ее выполнения во многих случаях. Однако, поскольку TurboC++ итак предпринимает мерыдля возможного размещения переменных в регистре, необходимость в явном задании ключевого слова register возникает редко.
Turbo C++ позволяет вам выбрать опции размещения переменных в регистрах в диалоговом поле Options \! Compiler \! Optimization. При выборе опции Automatic TurboC++ сделает попытку распределить регистры даже еслиспецификаторы класса памяти register не задавались.
Использование спецификатора класса памяти static
Спецификатор класса памяти static может использоваться в объявлениях функций и переменных с контекстом файла и локальным контекстом для обозначения внутреннего типакомпоновки. Static также указывает, что переменная должна иметьстатическую продолжительность существования. При отсутствии конструкторовили явныхинициализаторов статические переменные инициализируются 0 или null.
В С++ компоненты класса,статические данные, имеет то же значение длявсех вхождений класса. Члены класса, статические функции, не зависят от других вхождений класса.
Использование спецификатора класса памяти typedef
Ключевое слово typedef означает, что вы не объявляете объект, а определяете спецификатор нового типа данных. typedef включается в качестве спецификатора класса памяти вследствие синтаксических, а не функциональных аналогий.
static long int biggy;
typedef long int BIGGY;
Первое объявление создает 32-битовый объект типа long int, со статической продолжительностью существования и именем biggy. Второе объявление устанавливает идентификатор BIGGY в качестве спецификаторановоготипа, не создавая при этомкакого-либо объекта времени выполнения. BIGGY можно использовать в последующих объявлениях,там, где допустимо задаватьспецификатор типа. Например,
extern BIGGY salary;
имеет тот же эффект, что и
extern long int salary;
Хотя данный простой пример может быть равным образом реализован при помощи #define BIGGY long int, в более сложных случаях typedef позволяет добиться большего, нежели с помощью текстовых подстановок.
Важное замечание!
typedef не создает новых типов данных; это ключевое слово просто создает полезные мнемонические синонимы, или алиасы,для существующих типов. Это особенно полезно для упрощения сложных объявлений:
typedef double (*PFD)();
PFD array-pfd[10];
/* array_pfd это массив из 10 указателей на функции,
возвращающие значения типа double */
Нельзя использовать идентификаторы typedef со спецификаторами других типов:
unsigned BIGGY pay; /* НЕДОПУСТИМО */
Модификаторы
Помимо ключевых слов спецификатора класса памяти, объявление можетиспользовать конкретные модификаторы, предназначенные для изменения некоторых аспектов распределения памяти идентификатора/ объекта. В следующей таблице сведены модификаторы, имеющиеся в Turbo C++.
Модификаторы Turbo C++ Таблица 1.16
Модификатор Используется с Использование
const Только переменными Предотвращает изменения объекта
volatile Только переменными Предотвращает распределение
регистров и некоторые виды оптимизации. Предупреждает компилятор о том, что объект при вычислении может получить какиелибо изменения извне.
В С++ const и volatile расширены и включают классы и функции.
Расширения Turbo C++
cdecl Функции Устанавливает соглашения С пере-
дачи аргументов
cdecl Переменные Устанавливает учет регистра иден-
тификатора и ведущие знаки подчеркивания
pascal Функции Устанавливает соглашения пере-
дачи аргументов Паскаля
pascal Переменные отменяет учет регистра идентифи-
катора и ведущие знаки подчеркивания
interrupt Функции Функция компилируется с дополни-
тельным кодом управления регистром, необходимыми при написании обработчиков прерываний
near, Переменные Переопределяет умолчание типа
far, указатели указателя, задаваемое текущей
huge моделью памяти
_cs, Переменные Указатели сегмента;
_ds, указатели см. стр.199 оригинала
_es,
_seg,
_ss
near, Функции Переопределяет умолчание типа
far, функции, задаваемое текущей
huge моделью памяти
near, Переменные Определяет размещение объекта в
far, памяти
_export Функции Только OS/2. Turbo C++ это
игнорирует
_loadds Функции Устанавливает регистр DS на
текущий сегмент данных
_saveregs Функции Предохраняет все значения регис-
тров (кроме значений возврата)
во время выполнения функции
Модификатор const
Модификатор const предотвращает любые присваивания данному объекту, а также прочие побочные эффекты, такие как инкремент или декремент объекта. Указатель const неможет быть модифицирован, хотя сам объект, на который он указывает, может. Рассмотрим следующие примеры:
const float pi= 3.1415926;
const maxint = 32767;
char *const str= "Hello, world!"; // указатель константа
char const *str2= "Hello, world!"; // указатель на константу
Использование одного только модификатораconst эквивалентно const int.
С учетом этого, следующие операторы являются недопустимыми:
pi= 3.0; /* присвоение значения константе */
i= maxint++; /* инкремент константы */
str = "Hi, there!"; /* установка указателя str на что-то еще
Однако, отметим, что вызов функции strcpy(str,"Hi, there!") является допустимым, поскольку он выполняет посимвольное копирование из строкового литерала "Hi, there!" в адрес памяти, указываемый str.
В С++ const также "скрывает" объект const и предотвращает внешнюю компоновку. При необходимости нужно использовать extern const. Указатель на const не может быть присвоен указателю на неconst (в противном случае значению const могло было быть выполнено присвоение при помощи указателя на не -const.) Например,
char *str3 = str2 /* запрещено */
Модификатор функции прерывания interrupt
Модификатор interrupt специфичен для Turbo C++. Функции прерывания предназначены для работы с векторами прерывания 8086/8088. Turbo C++ компилирует функцию interrupt с дополнительным кодом входа и выхода, таким образом, чтобы сохранялись регистры AX, BX, CX, DX, SI, DI, ES иDS. Прочие регистры (BP, SP, SS, CS и IP) сохраняются как часть вызывающей последовательности С или как часть самого обработчикапрерываний. Для возвратафункция использует команду Iret, поэтому функция можетслужить для обслуживания аппаратных илипрограммных прерываний. Ниже показан пример типичного определения interrupt:
void interrupt myhandler()
(*
...
*)
Вы должны объявлять функции прерывания с типом void. Функции прерывания могут быть объявлены с любой моделью памяти. Для всех моделей памяти, кроме huge, DS устанавливается на сегмент данных программы. В случае модели huge DS устанавливаетсяна сегмент данных модуля.
Модификатор volatile
В C++ volatile имеетспециальное значение для функций компонентов класса. Если вы объявили объект volatile, вы можете использовать для него только функции компонентов volatile.
Модификатор volatile указывает, что данный объект может быть модифицирован не только вами, но также и извне вашей программы, например, подпрограммой прерывания или портом ввода/вывода. Объявление объекта volatile предупреждает компилятор, что тот не должен делать допущений относительно значения объекта во время расчета содержащих его выражений, поскольку его значение (теоретически) можетв любой момент измениться. Компилятор также не будет делать такую переменную регистровой переменной.
volatile int ticks;