Рубрики: КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

про компютерное железо, документация, языки программирования

Turbo C++ Version 1.0 Programmer’s Guide

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : TURBO C++ Version 1.0 Programmer’s Guide

enum team (* giants, cubs=3, dodgers = giants + 1 *);

константы установлены следующим образом:

giants = 0, cubs = 3, dodgers = 1

Значения констант не обязаны быть уникальными:

enum team (* giants, cubs = 1, dodgers = cubs — 1 *);

Допустимы также отрицательные инициализаторы.

Строковые литералы

— 20 —
Строковые литералы, известные также как строковые конс-
танты, образуют специальную категорию констант, используемых
для работы с фиксированными последовательностями символов.
Строковый литерал имееттип данных array ofchar и класспамя-
тиstatic, и записываетсякак последовательность произвольного
количества символов, заключенных в двойные кавычки:

«Это строковый литерал!»

Нулевая (пустая) строка записывается как «».

Символы внутри двойных кавычек могут включатьуправляю-
щие последовательности (см. стр. 13 оригинала). Например,
данный код,

«\t\t\»Имя \»\\\tАдрес\n\n»

распечатается следующим образом:

«Имя «\ Адрес

Слову «Имя » будет предшествовать два символа табуля-
ции; слову Адрес предшествуетодин символтабуляции. Строка
заканчиваетсядвумя символами новой строки. Последователь-
ность \» обеспечивает вывод внутренних кавычек.

Строка литерала хранится в памяти как заданная последо-
вательность символов,плюс конечный пустой символ (‘\0’). Ну-
левая строка хранится в виде одного символа ‘\0’.

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

#include

main()
(*
char *p;

p = «Это пример того, как Turbo C++»
» автоматически\nвыполняет для вас конкатенацию»
» очень длинных строк,\nчто позволяет получить»
» более красивые программы.»;
printf(*p*);
*)

На выходе программы будет:

Это пример того, как Turbo C++ автоматически
выполняет для вас конкатенацию очень длинных строк,
что позволяет получить более красивые программы.

Для расширения строковой константы за границы строки в
качестве символа продолжения можно использовать обратную
наклонную черту (\):

put(«В действительности \
это однострочная строка символов»);
Константы и их внутреннее представление

ANSI C говорит о том, что размер и численный диапазон
базовых типовданных( и различных их модификаций) зависят от
конкретной реализации компилятора и в целом от архитектуры
компьютера, на котором он установлен. Базовыми компьютерами
дляTurbo C++ являются компьютеры семействаIBM PC (и совмес-
тимые с ними), поэтому выбор внутреннего представления раз-

— 21 —
личных типов данных в целом определяется архитектурой мик-
ропроцессоров 8088 и 80×86. В следующей таблице сведены
размеры и соответствующие диапазоны значений для типов дан-
ных, определяемых в Turbo C++. Дополнительную информацию об
этих типах данных см. на стр. 39 оригинала. Внутреннее
представление типов данных см. на рис.1.

Типы данных, размеры и диапазоны значений Таблица 1.9
————————————————————
Тип Размер Диапазон Примеры применения
————————————————————
unsigned char8 0 до 255 Малые числа и полный

набор символов PC

char8 -128 до 127 Самые малые числа и
ASCII-символы

enum 16 -32,768 до 32,767 Упорядоченные наборы
значений

unsigned int 16 0 до 65,535 Большие числа и циклы

short int 16 -32,768 до 32,767 Счетчики, малые числа,
управление циклами

int 16 -32,768 до 32,767 Счетчики, малые числа,
управление циклами

unsigned long 32 0 до 4,294,967,295 Астрономические
расстояния

long 32 -2,147,483,648 до 2,147,483,647
Большие числа, население

-38 38
float 32 3.4 x 10 до 3.4 x 10
Научные расчеты (точность
7 разрядов)

-308 308
double 64 1.7 x 10 до 1.7 x 10
Научные расчеты (точность
15 разрядов)

-4932 4932
long double 80 3.4 x 10 до 1.1 x 10
Финансовые расчеты
(точность 19 знаков)

near pointer 16 Не существует Манипулирование адресами
памяти

far pointer 32 Не существует Манипулирование адресами
памяти вне текущего
сегмента
————————————————————

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Turbo C++ Version 1.0 Programmer’s Guide

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : TURBO C++ Version 1.0 Programmer’s Guide

Модификаторы типа функции

Модификаторы near, far и huge могут также использовать-
сякак модификаторы типа функции; т.е., они могут модифициро-
вать, помимо указателей данных, функции и указатели функций.
Кроме того,для модификации функций могут служить модификато-
ры _export, _loadds и _saveregs.

Модификаторы функций near, far и huge могут комбиниро-
ваться с модификаторами cdecl или pascal, но не с interrupt.

Функции типа huge полезны для интерфейса с кодами на
языке ассемблера, не использующими такое же,как вTurbo С++,
распределение памяти.

Функции,не имеющие модификатора interrupt, могут быть
объявлены как near,far или hugeс тем, чтобы переопределить
установки текущей модели памяти по умолчанию.

Функция near использует ближние (near) вызовы; функ-
цияfar или huge использует дальние (far) команды вызова.

— 52 —

В случае моделей памяти tiny, small и compact функция,
где это не было задано явно, имеет по умолчанию тип near. В
моделях medium и large по умолчанию функция имеет тип far. В
модели памяти huge по умолчанию используется тип huge.

Функция huge аналогична функции far, за исключением то-
го, что при входе вфункцию huge регистрDS устанавливается на
адрес сегмента данных исходного модуля, нодля функции far
остается неустановленным.

Модификатор _export лексически анализируется, но игно-
рируется. Он обеспечивает совместимость с исходными модуля-
ми, написанными для OS/2. Для программ в DOS модификатор
_export никакого значения не имеет.

Модификатор _loadds указывает, что функция должна уста-
навливатьрегистр DS аналогично тому, как это делает функция
huge, но не подразумевает вызовов near или far. Таким обра-
зом, _loadds far эквивалентно объявлению huge.

Модификатор _saveregsзаставляет функцию сохранитьвсе
значения регистров и затем восстановить их перед возвра-
том(за исключением явных значений возврата, передаваемых в
таких регистрах AX или DX.)

Модификаторы _loadds и_saveregs полезны при написании
подпрограмм интерфейса нижнего уровня, как например, подп-
рограммы поддержки мыши.

Сложные объявления и деклараторы

Синтаксис декларатора см. на стр.35 оригинала.Определе-
ние включает в себя деклараторы идентификаторов и функций.

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

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

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

спецификатор-класса-памятиtype D1, D2;

указывает, что каждое вхождение D1 или D2 в выражение
будет рассматриваться как объект типа «type» и с заданным
«классом-памяти». Тип имени-декларатора, входящего в декла-
ратор, должно быть некоторой фразой, содержащей type, напри-
мер «type», «pointer to type», «array of type», «function
returning type» или «pointer to function returning type», и
т.д.

Например, в объявлениях

int n, nao[], naf[3], *pn, *apr[], (*pan)[], &nr=n

— 53 —
int f(void), *frp(void), (*pfn)(void);

каждый из деклараторов мог бы быть использован в ка-
честве значения переменной (правой части) (или, возможно, в

некоторых случаях в качестве именующего выражения (левой
части) ) в выражениях, где допустим один объект int. Типы
встроенных идентификаторов берутся из их деклараторов следу-
ющим образом:

Сложные объявления Таблица 1.17
————————————————————
Синтаксис Подразумеваемый тип имени Пример
————————————————————
type имя; type int count;
type имя[] (открытый) массив array of type int count[1];
type имя[3]; Фиксированный массив из трех int count[3];
элементов типа type
(name[0],name[1],name[3])
type *имя; Указатель на type int *count;
type *имя[]; (открытый) массив указателей int *count[];
type *(имя[]) То же самое int *(count[]);
type (*имя)[]; Указатель на (открытый) массив int
(*count)[];
типа type
type &имя; Ссылка на тип type (только С++) int &count;
type имя(); Функция, возвращающая тип type int count();
type *имя(); Функция, возвращающая указатель int *count();
на тип type
type *(имя()); То же самое int *(count());
type (*имя)(); Указатель на функцию, возвращающую int
(*count)();
тип type
————————————————————

Отметим необходимость круглых скобок в (*имя)[] и
(*имя)(), поскольку приоритет декларатора массива [] и дек-
ларатора функции () выше, чем декларатора указателя *. Круг-
лые скобки в *(имя[]) опциональны.

Указатели

Обсуждение создания ссылок и обращения по ссылкам (ра-
зыменования) см. на стр.80 оригинала.

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

Два этиклассауказателей имеют отличные друг от друга
свойства, назначения и правила манипулирования, хотя и те и
другие разделяют между собойопределенные операцииTurbo C++.
Вообще говоря, указатели функций используются для доступа к
функциям и для передачиодних функцийдругим в качествеаргу-
ментов; выполнение арифметических операцийс указателямифунк-
ций не допускается. И напротив, указателиобъектов при скани-
ровании массивов или более сложных структур памяти регулярно
инкрементируются и декрементируются.

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

Указатели объектов

— 54 —
«Указатель на объект типа type» содержит адрес (то есть
указывает) объекта с типом type. Поскольку указатель сам по
себе является объектом, то вы можете установить указатель на
указатель (и т.д.). В число прочих объектов,на которые обыч-
но устанавливается указатель, входят массивы, структуры,объ-
единения и классы.

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

Указатели функций

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

Указатель функции имеет тип «указатель функции, возвра-
щающей тип type», где type есть тип возвращаемых функцией
данных.

В С++, где контроль типов данных болеестрогий, указа-
тель функции имеет тип «указатель функции принимающей агру-
менты типа type и возвращающей тип type». Действительно, в С
функция, определенная с типами аргументов, также будет иметь
данный, более узкий тип. Например,

void (*func)();

В С это будет указатель функции, не возвращающей ника-

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Turbo C++ Version 1.0 Programmer’s Guide

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : TURBO C++ Version 1.0 Programmer’s Guide

выражение-отношения
выражение-типа-равенства == выражение-отношения
выражение-типа-равенства != выражение-отношения

Операция проверки равенства ==

В выражении E1 == E2 операнды должны удовлетворять

— 84 —
одному из следующего набора условий:

1. Оба значения Е1 и Е2 — арифметического типа.

2. Оба значения Е1 и Е2 являются указателями квалифици-
рованных или неквалифицированных версий совместимых типов.

3. Одно из значений, Е1 или Е2, является указателем
объекта неполного типа, а второй — указателем на квалифици-
рованную или неквалифицированную версию void.

4. Одно из значений, Е1 или Е2, является указателем, а
второе — константой типа пустого указателя.

Если Е1 и Е2 имеют тип, являющийся допустимым типом для
операций отношения, то применимы правила, подробно описанные
для операций отношения типа Е1 < E2, E1

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Turbo C++ Version 1.0 Programmer’s Guide

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : TURBO C++ Version 1.0 Programmer’s Guide

условное-выражение

Выражения с константами не могут содержать приводимых
ниже операций, если эти операции не содержатся в операнде
операции sizeof:

— присваивание
— декремент
— вызов функции
— запятая
Описание операций

Операциями называются лексемы, вызывающие некоторые вы-
числения спеременными ипрочими объектами, указанными в выра-
жении. Turbo C++ имеетособенно богатый набор операций, вклю-
чающий в себя помимо обычных арифметических и логических
операций средства манипуляции с данными на битовом уровне,
доступа к компонентам структур иобъединений, а такжеоперации
с указателями (установка и обращение по ссылке).

Расширения C++ предлагают дополнительные операции для

— 23 —
доступа к компонентам класса и их объектам, атакже механизм
перегрузки операций. Перегрузка позволяет переопределять
действие любых стандартных операций применительно к объектам
заданного класса. В данном разделе мы ограничимся рассмотре-
нием стандартных операций TurboC++. Перегрузка рассматрива-
ется, начиная со стр.124 оригинала.

После определения стандартных операций мы обсудим типы
данных и объявления, а также объясним, как они влияют на
действие каждой операции. Затем мы перейдем к рассмотрению
синтаксиса построения выражений с помощью операций, пунктуа-
торов и объектов.

Операции в Turbo C++ определяются следующим образом:

операция: одно из

[] () . -> ++ —
& * + — тильда !
sizeof / % > < > = == != ^
\! && \!\! ?: = *=
/= %= += -= =
&= ^= \!= , # ##

Операции # и ## используются только препроцессором (см.
стр. 133 оригинала).

Следующие операции являются специфичными для C++:

:: .* ->*

За исключением операций [], () и ?:, служащих для запи-
си выражений в скобках, многосимвольные операции рассматри-
ваются в качестве одной лексемы. Лексема одной и той же опе-
рации может иметьнесколько интерпретаций, в зависимости от
контекста. Например,

A * B Умножение
*ptr Обращение по ссылке

A & B Поразрядное И
&A Операция адресации
int & Модификатор указателя (C++)

label: Метка оператора
a ? x : y Условный оператор

void func(int n); Объявление функции
a = (b+c)*d; Выражение со скобками

a, b, c; Выражение с запятой
func(a, b, c); Вызов функции

a = -b; Поразрядное вычитание (дополнение до
единицы)
-func() (*delete a;*) Деструктор (C++)

Унарные операции

& Операция адресации
* Операция обращения по ссылке
+ Унарный плюс
— Унарный минус
тильда Поразрядное дополнение (дополнение до
единицы)
! Логическое отрицание

— 24 —
++ Префикс: пред- инкремент;
Постфикс: пост- инкремент
— Префикс: пред- декремент;
Постфикс: пост- декремент
Бинарные операции

Операции типа сложения + Бинарный плюс (сложение)
— Бинарный минус (вычитание)

Операции типа умножения * Умножение
/ Деление
% Остаток от деления

Операции сдвига > Сдвиг вправо

Поразрядные операции & Поразрядное И
^ Поразрядное исключающее ИЛИ
\! Поразрядное включающее ИЛИ

Логические операции && Логическое И
\!\! Логическое ИЛИ

Операторы присваивания = Присваивание
*= Присвоить произведение
/= Присвоить частное
%= Присвоить остаток
+= Присвоить сумму
-= Присвоить разность
= Присвоить сдвиг вправо
&= Присвоить поразрядное И
^= Присвоить поразрядное исключающее
ИЛИ
\!= Присвоить поразрядное ИЛИ

Операции отношения < Меньше > Больше
= Больше или равно

Операции равенства == Равно
!= Не равно

Операции выбора . Прямой селектор компонента
компонента -> Косвенный селектор компонента

Операции с компонентами :: Доступ/разрешение контекста
класса .* Обращение через указатель
к компоненту класса
->* Обращение через указатель
к компоненту класса

Условные операции a ? x : y «Если a то x иначе y»

Операция запятой , Вычислить, например, a, b, c
слева — направо

Функции этих операций,также как их синтаксис, приоритет
и свойства ассоциативности рассматриваются, начиная со стр.
73 оригинала.

Пунктуаторы

В TurboC++ пунктуаторы, также называемые разделителями,
определяются следующим образом:

— 25 —
пунктуатор: одно из
[ ] ( ) (* *) , ; : … * = #

Квадратные скобки

[] (открывающая и закрывающая квадратные скобки) указы-
вают на индексы одно- и многомерных массивов:

char ch, str[] = «Stan»
int mat[3][4]; /* матрица 3 x 4 */
ch = str[3]; /* 4-й элемент */

Круглые скобки

() (открывающая и закрывающая круглыескобки) группируют
выражения, выделяют условные выражения и указывают на вызовы
функций и параметры функций:

d = c * (a + b); /* переопределение нормального приори-
тета */
/* выполнения операций */
if (d == z) ++x; /* важно при использовании условных
операций */
func(); /* вызов функции без аргументов */
int (*fptr)(); /* объявление указателя функции */
fptr = func; /* отсутствие () означает указатель функ-
ции */
void func2(int n); /* объявление функции с аргументами */

Рекомендуетсяиспользовать круглые скобки в макроопреде-
лениях, что позволит избежать возможных проблем с приорите-
тами операций во время расширения:

#define CUBE(x) ((x) * (x) * (x))

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

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Turbo C++ Version 1.0 Programmer’s Guide

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : TURBO C++ Version 1.0 Programmer’s Guide

ких значений. В С++ это указатель функции, не принимающей
никаких аргументов и не возвращающей никаких значений. В
примере

void(*func)(int);

*func это указатель функции, принимающей аргумент int и
не возвращающей никаких значений.

Объявления указателей

Подробное описание типа void см. на стр.39 оригинала.

Объявление указателя всегда должно устанавливать его на
некоторый конкретный тип, даже если этот тип void (что фак-
тическиозначает указатель на любой тип). Однако, уже после
объявления указатель обычно может быть переназначен на объ-
ект другого типа. Turbo C++ позволяет переназначать указате-
ли без приведения в соответствие типа, но компилятор выдаст
при этом предупреждение, если только первоначально указатель
не был объявлен с типом void. В С (но не в С++) вы можете
назначить указатель void* на указатель, не имеющий тип
void*.

Если type есть любой предопределенный или определенный
пользователем тип, включая void, то объявление

type *ptr;/* Опасно — неинициализированный указатель */

— 55 —
объявит ptr как «указатель на тип type». К объявленному
таким образомобъекту ptr применимы все правила, связанные с
контекстом, продолжительностью и видимостью.

Указатель со значением null это адрес, гарантированно
отличный от любого допустимого указателя, используемого в
программе. Присвоение указателю целой константы 0 присваива-
ет указателю значение null.

Указатель типа «указатель на void» не следует путать с
нулевым (null) указателем. Объявление

void *vptr;

объявляет, что vptr — это родовой указатель, которому-
может быть присвоено любое значение «указатель на тип type»
без выдачи компилятором сообщений. Присвоения без правильно-
го приведения типов между «указателем на тип type1» и «ука-
зателем на тип type2», где type1 и type2 это различные типы,
может вызвать предупреждение или ошибку компилятора. Если
type1 это функция, а type2 нет (или наоборот), присваивания
указателей недопустимы. Если type1 это указатель на void,
приведения типов не требуется. Если type2 это указатель на
тип void, то в С приведение не нужно.

Ограничения присвоения также существуют относительно
указателей разных размеров (near, far и huge). Можно присво-
ить меньший указатель большему, не вызвав ошибки, но нельзя
выполнить обратную операцию, не выполнив явную операцию при-
ведения. Например,

char near *ncp;
char far *fcp;
char huge *hcp;
fcp = ncp; // допустимо
hcp = fcp; // допустимо
fcp = hcp; // недопустимо
scp = fcp; // недопустимо
scp = (char nesr*)fcp; // теперь допустимо
Указатели и константы

Указатели или указываемые ими объекты могут быть объяв-
лены с модификатором const. Присвоение объекту, объявленно-
мукак const, не допускается. Также не допускается создание
указателя, который может нарушить запрещение на модификацию
объекта типа константы. Рассмотрим следующие примеры:

int i; // i это целое;
int * pi; // pi это указатель на i
// (неинициализированный)
int * const cp = &i; // cp это указатель-константа на int
// const
int ci = 7; // ci это константа int const
int * pci; // pci это указатель наконстанту ci
const int * const cpc = &ci; // cpc это указатель-конс-
танта
// на константу int

Следующие присвоения допустимы:

i = ci; // Присвоить const int переменной int
*cp = ci; // Присвоение const int объекту, на
// который указывает
// указатель-константа
++pci; // Инкремент указателя на константу
pci = cpc; // Присвоение константы-указателя-на

// константу указателю-на-константу

— 56 —

Следующие присвоения недопустимы:

ci = 0; // Присвоение значений константе
// const int недопустимо
ci—; // Изменение константы недопустимо
*pci = 3; // Присвоение объекту, на который
// указывает указатель-на-константу
// недопустимо
cp = &ci; // Присвоение константе-указателю,
// даже если ее значение не будет
// изменено, недопустимо
cpc++; // Изменять указатель-константу
// недопустимо
pi = pci; // Если бы такое присвоение было
// разрешено, вы могли бы присваивать
// *pci (константе), присваивая *pi
// что недопустимо

Аналогичные правила относятся и к модификатору
volatile.Отметим, что const и volatile могут появляться в
качестве модификаторов одного и того же идентификатора.

Арифметические операции с указателями

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

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

При выполнении арифметических операций с указателями
предполагается, что указатель указывает на массив объектов.
Таким образом, если указатель объявлен как указатель на
type, то прибавление к нему целочисленного значения переме-
щает указатель на соответствующее количество объектов type.
Если type имеет размер 10 байтов, то прибавление целого чис-
ла 5 к указателю этого типа перемещает указатель в памяти на
50 байт. Разность представляет собой число элементов масси-
ва, разделяющих два значения указателей. Например, если ptr1
указывает на третий элемент массива, а ptr2 на десятый, то
результатом выполнения вычитания ptr2 — ptr1 будет 7э

Когда с «указателем на тип type» выполняется операция
сложения или вычитание целого числа, то результат также бу-
дет «указателем на тип type». Ецли type неявляется массивом,
то операнд указателя будет рассматриваться как указатель на
первый элемент «массива типа type» длиной sizeof(type).

Конечно, такого элемента, как «указатель на следующий
за последним элемент», однако указатель может принимать это
значение. Если P указывает на последний элемент массива, то
значение P+1 допустимо, но P+2 неопределено. Если P указыва-
ет на элемент за последним элементом массива, то допустимо
значение P-1, когда указатель установлен на последний эле-
мент массива. Однако установка указателя на элемент за пос-
ледним элементом массива ведет к непредсказуемым результатам
работы программы.

Для информации:P+n можно представить себе как перемеще-
ние указателя на (n*sizeof(type)) байт вперед, пока указа-

— 57 —
тель остается в допустимых границах (не далее первого за
концом массива элемента).

Вычитание междудвумя указателями на элементы одного и
того же массива дает интегральное значение типа ptrdiff_t,
определенное в stddef.h (signed long для указателей huge и
far; signed intдля всех прочих). Данное значение представля-
ет собой разность между индексами двух указанных элементов,
при условии вхождения в диапазоне ptrdiff_t. В выражении
P1P2, где P1 и P2 это указатели на тип type (или указатели
на квалифицированный тип), P1 и P2 должны указывать на су-
ществующие элементы или на следующий за последним элемент.
если P1 указывает на i-й элемент, а P2 указывает на j-й эле-
мент, то P1-P2 имеет значение (i-j).

Преобразования указателей

Указатели одного типа могут бытьпреобразованы в указа-
тели другого типа при помощи следующего механизма приведения
типов:

char *str
int *ip
str = (char*)ip;

В более общем виде, приведение (type*) преобразует ука-
затель в тип «указатель на тип type».

Объявления ссылок в С++

Ссылочные типы С++ тесно связаны с типами указателей.

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Turbo C++ Version 1.0 Programmer’s Guide

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : TURBO C++ Version 1.0 Programmer’s Guide

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

В случае 6 типом результата будет тип операнда, не яв-
ляющегося указателем на void.

Операции присвоения

Существует одиннадцать операций присвоения. самым
простым из них является операция =; остальные называются
составными операциями присвоения.

— 87 —
Синтаксис операций присвоения следующий:

выражение-присвоения:
условное-выражение
унарное-выражение операция присвоения выражение-присво-
ения

операция-присвоения: одно из
= *= /= %= += -=
= &= ^= \!=

Простая операция присвоения =

В выражении Е1 = Е2 Е1 должен быть модифицируемым име-
нующим выражением. Значение Е2 после преобразования к типу
Е1 помещается в объект, задаваемый Е1 (замещая предыдущее
значение Е1). Значение выражнения присвоения это значение Е1
после присвоения. Само по себе выражение присвоения не явля-
ется именующим значением.

ОперандыЕ1 и Е2 должны удовлетворять одному из следую-
щего набора правил:

1. Е1 имеет квалифицированный или неквалифицированный
арифметический тип, а Е2 имеет арифметический тип.

2. Е1 имеет квалифицированную или неквалифицированную
версию типа структуры или объединения, совместимого с типом
Е2.

3. Е1 и Е2 это указатели на квалифицированную или нек-
валифицированную версии совместимых типов , а тип, на кото-
рый указывает левый операнд, имеет все квалификаторы типа,
на который указывает правый операнд.

4. Один из операндов, Е1 или Е2, является указателем
объектаили неполного типа, а другой — указвтелем на квалифи-
цированную или неквалифицированную версию void. Тип, на ко-
торый указываетлевый операнд, имеет все квалификаторы типа,
на который указывает правый операнд.

5. Е1 является указателем, а Е2 — константой типа пус-
того указателя.

Составные операции присвоения

Составные операции вида операция=, где «операция» — это
один из десяти символов операции * / % + — > & ^ \!, ин-
терпретируются следующим образом:

Е1 операция= Е2

имеет тот же эффект, что и

Е1 = Е1 операция Е2

за исключением того, что именующее значение Е1

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Turbo C++ Version 1.0 Programmer’s Guide

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : TURBO C++ Version 1.0 Programmer’s Guide

Фигурные скобки

(**) (Открывающие и закрывающие фигурныескобки) обозна-
чают начало и конец составного оператора:

if (d == z)
(*
++x
func();
*)

Закрывающая фигурная скобка служит терминатором состав-
ного оператора, поэтому (;) (точка с запятой) после *) не
требуется, за исключением структур или объявлений классов.
Часто точка с запятой недопустима, как например в случае

if (оператор)
(**); /* недопустимое использование точки с запятой */
else

Запятая

Запятая (,) отделяет элементы списка аргументов функции:

void func(int n, float f, char ch);

Запятая часто используется как операция в «операции с

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

func(i, j); /* вызов функции с двумя аргументами */
func((exp1, exp2), (exp3, exp4, exp5)); /* также вызов
функции с двумя аргументами */

Точка с запятой

Точка с запятой (;) служит терминатором оператора. Лю-
бое допустимое выражениеС (включая и пустое выражение), за
которым следует (;), интерпретируется как оператор, называе-
мый оператором выражения. Выражениевычисляется, а его значе-
ние отбрасывается. Если такое выражение не имеетпобочных эф-
фектов, то TurboC++ может его проигнорировать.

a + b; /* a + b вычисляется, но полученное значение
теряется */
++a; /* имеется побочный эффект для a, но результат ++a
*/
/* теряется */
; /* пустое выражение = нулевой оператор */

Точки сзапятой частоиспользуются для создания пустых
операторов:

for (i = 0; i < t; i++) (* ; *) Двоеточие Двоеточие (:) служит для обозначения оператора с меткой: stsrt: x=0; ... goto stsrt; ... switch (a)(* case 1: puts("Первый"); break; case 2: puts("Второй"); break; ... default: puts("Ни тот, ни другой!"); break; *) Метки рассматриваются на стр.92 оригинала. Многоточие Многоточие (...) представляет собой три последовательно расположенные точки без пробелов между ними. Многоточия ис- пользуются в списках формальных аргументовпрототипов функций для обозначения переменногочисла аргументов, либо аргументов с изменяющимся типом: void func(int n, char ch,...); Данное объявление указывает, что func будет определена таким образом, что вызовы ее должны содержать как минимум два аргумента, int и char,но также могут иметь и любое число дополнительных аргументов. В С++ запятую, предшествующую многоточию, можно опустить. - 27 - Звездочка (объявление указателя) Звездочка (*) в объявлении переменной обозначает созда- ние указателя на тип: char *char_ptr; /* объявление указателя на тип char */ Можно объявить указатели с несколькими уровнями косвен- ности, что обозначается соответствующим количеством звездо- чек: int **int_ptr; /* указатель на указатель на int */ double ***double_ptr /* указатель на указатель на указатель на тип double */ Звездочка также используется в качестве операции обра- щения через указатель, либо операции умножения: i = *int_ptr; a = b * 3.14; Знак равенства (инициализатор) Знак равенства (=) разделяет объявления переменных от списков инициализации: char array[5] = (* 1, 2, 3, 4, 5 *); int x = 5; В функциях С никакой код не может предшествовать ника- ким объявлениям переменных. В С++ объявления любого типа мо- гут находиться (с некоторыми ограничениями) в любой точке внутри кода. В списке аргументов функции С++ знак равенства указыва- ет на значение параметра по умолчанию: int f(int i = 0) (* ... *) /* параметр i имеет значение по умолчанию ноль */ Знак равенства используется также как операция присвое- ния в выражениях: a = b + c; ptr = farmalloc(sizeof(float)*100); Знак фунта (директива препроцессора) Знак фунта (#) означает директиву препроцессора, если она является первым не-пробельным символом встроке. Он зада- ет действие компилятора, не обязательно связанное с генера- цией кода. Более подробно директивы препроцессора описаны на стр.133 оригинала. # и ## (двойной знак фунта) также используются как опе- рации замены и слияния лексем на фазе сканирования кода препроцессором. Объявления В данном разделе кратко рассматриваются концепции, свя- занные с объявлениями: объектов, типов, классов памяти, кон- текста, видимости, продолжительности и типом компонов- ки.Преждечем перейти к рассмотрению полного синтаксиса объявления, важно иметь общее представление об этих поняти- ях. - 28 - Контекст, видимость, продолжительность и тип компоновки определяют части программы,из которых могут быть сделаны до- пустимые ссылки на идентификатор сцельюдоступа к соответс- твующему объекту. Контекст обсуждаетсяна стр.29 оригинала, видимость - на стр.30; продолжительность рассматривается, начиная со стр. 31, а тип компоновки - на стр.32. Объекты Объектом называется идентифицируемая область памяти, которая может содержать фиксированное значение переменной (или набор таких значений). (Используемое в данном случае слово "объект" не следует путать с более общим термином, ис- пользуемым в объектно-ориентированных языках - см. главу 5, "Введение в С++" в документе "Начало работы".) Каждая вели- чина имеет связанное с ней имя и тип (который также называют типом данных). Имя используется для доступа к объекту. Имя может являться простым идентификатором, либо сложнымвыраже- нием, уникальным образом "указывающим" на данный объект. Тип используется для - для определения требуемого количества памяти при ее исходном распределении, - для интерпретации битовых коды, находимых в объектах при последующих к ним обращениях, - а также в многочисленных ситуациях контроля типа, требуемого для обнаружения возможных случаев недопустимого присваивания. Turbo C++ поддерживает многие стандартные (предопреде-

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Turbo C++ Version 1.0 Programmer’s Guide

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : TURBO C++ Version 1.0 Programmer’s Guide

Ссылочные типы создают алиасы объектов и позволяют переда-
вать функциям аргументы по ссылке. Традиционно передача ар-
гументов в С выполняется только по значению. В С++ переда-
вать аргументы можно как по значению, так и по ссылке.
Полную информацию см. в разделе «Ссылки» на стр.98 оригина-
ла.
Массивы

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

Объявление

type декларатор []

объявляет масив, состоящий из элементов типа type. Мас-
сив в С состоит из непрерывной области памяти, по размеру
позволяющей в точности разместить все его элементы.

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

Многомерные массивы создаются путем объявления массивов
из элементов типа массив. Таким образом, двумерный массив из
пяти строк и семи столбцов с именем alpha объявляется следу-
ющим образом:

type alpha [5] [7];

В определенном контексте первый декларатор массива из
нескольких может не иметь выражения в квадратных скобках.

— 58 —
Такой массив имеет неопределенный размер. Контекстом, где
допустимо такое положение, является тот случай, когдадля ре-
зервирования памяти размер массива не требуется. Например,
для объявление объекта типа массива extern точный размер
массива не требуется; не требуется он и при передаче функции
параметра типа массива. Будучи специальным расширением ANSI
C, Turbo C также позволяет объявлятьв качестве последнего
элемента структуры массив неопределенного размера. Такой
массив не увеличивает размера структуры, а для того, чтобы
обеспечить правильное выравнивание структуры, ее можно спе-
циально дополнить символами-заполнителями. Такие структуры
обычно используются при динамическом распределении памяти,
когда для правильного резервирования области памяти к разме-
ру структуры следует явно прибавить фактический размер необ-
ходимого массива.

За исключением использования массива в качестве операн-
да операции sizeof или &, выражение с типом массива
преобразуется в константу-указатель на первый элемент масси-
ва.

Функции

Функции представляют собой центральный вопрос програм-
мирования на Turbo C++. Такие языки программирования, как
Паскаль, делают различие между процедурами и функциями. В
Turbo C++ функции играют обе роли.

Объявления и определения

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

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

В С++ вы должны всегда пользоваться прототипами функ-
ции. Мы рекомендуем также всегда использовать их и в С.

Данная функция может быть объявлена в программе нес-
колько раз, при условии, что эти объявлениясовместимы. Неоп-
ределяющие объявления функции, использующие формат прототипа
функции предоставляют Turbo C++ детальную информацию о пара-
метрах, что позволяет лучшее управление числом аргументов,
контролем их типа и преобразованиями типов.

За исключением перегрузки функции в С++, допустимым яв-
ляется только одно объявление данной функции в программе.
Объявления, если они имеются, должны соответствовать опреде-
лению функции. (Существенным различием между определением и
объявлением является то, что определение содержит собственно
тело функции.)

Объявления и прототипы

В оригинальном стиле объявлений Кернигэна и Ритчи функ-
ция могла быть либо объявлена неявно, по ее вызову, либо яв-
но:

func()

где type — это опциональный тип возврата, по умолчанию

— 59 —
равный int. Можно объявить функцию с любым типом возврата,
за исключениемтипов массива или функции. Такой подход не
позволяет компилятору контролировать соответствие типа или
количества используемыхпри вызове функции аргументов объяв-
лению.

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

func(список-деклараторов-параметров)

При помощи IDE или опции компилятора командной строки
можно разрешить выдачу следующего предупреждения: «Function
called without a prototype» («Функция вызывается без прото-
типа»).

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

long lmax(long v1, long v2); /* прототип */
main()
(*
int limit = 32;
char ch = ‘A’;
long mval;
mval = lmax(limit,ch): /* вызов функции */

Поскольку данная программа имеет прототип функции для
lmax, данная программа преобразовывает limit и ch к типу
long по стандартным правилам присвоения, прежде чем помес-
тить их в стекдля вызова lmax.Без прототипа функции limit и
ch были бы помещены в стек как целое и символьное значения,
соответственно; в этом случае стек, переданный lmax, не со-
ответствовал бы по размеру и содержимому тому, что ожидает
на входе lmax, что привело бы к возникновению проблем. Клас-
сический стиль объявлений не позволяет выполнять контроль
типа и числа параметров, поэтому использование прототипов
функций существенно упрощает отслеживаниепрограммных ошибок.

Прототипы функций также упрощают документирование кодов
программы. Например, функция strcpy принимает два параметра:
исходную строку и строку назначения. Вопрос, где какая из
них? Прототип функции

char *strcpy(char *dest, char *source);

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

Декларатор функции в круглых скобках, содержащий единс-
твенное словоvoid, указывает на функцию, вообще не
принимающую аргументов:

func(void);

В С++ func() также означает функцию, не принимающую ар-
гументов.

stdarg.h содержит макросы, которые можно использовать в
функциях, определяемых пользователем, с переменным числом

— 60 —
параметров.

Прототип функции обычно объявляет функцию, принимающую
фиксированное число параметров. Для функции С, принимающей
переменное число параметров (например, printf) прототип
функции может заканчиваться многоточием (…), например:

f(int *const, long total, …)

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

Ниже приводятся примеры деклараторов функций и прототипы:

int f(); /* В С это функция, возвращащая int, без ин-
формации о параметрах. Это «классический стиль» Кернигэна и
Ритчи */

int f(); /* В С++ это функция, не принимающая аргументов */

int f(void); /* Функция, возвращающая int и не принима-
ющая параметров */

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30