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

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

Turbo C++ Version 1.0 Programmer’s Guide

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

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

С учетом этого, следующие операторы являются недопустимыми:

pi= 3.0; /* присвоение значения константе */
i= maxint++; /* инкремент константы */
str = «Hi, there!»; /* установка указателя str на
что-то еще

Однако, отметим, что вызов функции strcpy(str,»Hi,
there!») является допустимым, поскольку он выполняет посим-
вольное копирование из строкового литерала «Hi, there!» в
адрес памяти, указываемый str.

В С++ const также «скрывает» объект const и предотвра-
щает внешнюю компоновку. При необходимости нужно использо-
вать extern const. Указатель на const не может быть присвоен

— 49 —
указателю на не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;
interrupt timer()
(*
ticks++;
*)
wait(int interval)
(*
ticks = 0;
while (ticks < interval); // не делает ничего Эти подпрограммы (предполагается, что timer правильно связана с аппаратным прерыванием часов) реализуют выдержкупо времени между"тиканьем" часов, заданную аргументом interval. Высоко оптимизированный компилятор не может загружать значе- ние ticks в проверку выхода из цикла while, так как цикл не изменяет значения ticks. Модификаторы cdecl и pascal Turbo C++ позволяет вашим программам легко вызывать - 50 - подпрограммы, написанные на других языках, и наоборот.При смешанном программировании приходится иметь дело с двумя важными вопросами: идентификаторы и передача параметров. В Turbo C++ все глобальные идентификаторы сохраняются в своем исходном виде (строчные, заглавныебуквы и их комбина- ции) с присоединенным в начале идентификатора знакомподчер- кивания (_), если вы не выберете опцию-u- (GenerateUnderbars...Off) в диалоговом поле Options \! Compiler \! Code Generation). На стр.32 оригинала рассказано, как использовать extern,что позволяет ссылаться на имена С из программы на C+ +. pascal В Паскале глобальные идентификаторы не сохраняются в своем исходном виде и не имеют первым символом знак подчер- кивания. Turbo C++ позволяют объявлять любые идентификаторы как имеющие тип pascal; тогда такойидентификатор преобразо- вывается к верхнему регистру, и ему непредшествует знак под- черкивания. (Если идентификатор является функцией,то что также влияет на используемую последовательность передачи па- раметров;подробности см. на стр. 51 оригинала, "Модификаторы типа функции".) Опция компилятора -p (Calling Convention...Pascal в ди- алоговом поле Options \! Compiler \!Code Generation) вызыва- ет обработку функций (и указателей на эти функции) как если бы они имели тип pascal. Модификатор pascal специфичен для Turbo C++; он пред- назначен для функций (и указателей функций), использующих последовательность передачи параметров Паскаля. Кроме того, функции, объявленные с типом pascal, могут тем не менее вы- зываться из подпрограмм С, если последним известно, что дан- ная функция имеет тип pascal. pascal putnums(int i, int j, int k) (* printf("And the answers are: %d, %d, and %j\n",i,j,k); *) Функции типа pascal немогут принимать переменное число аргументов, в отличие от таких функций, как printf. Поэтому в определении функции типа pascal использовать многоточие (...) нельзя. cdecl Программа main должна быть объявлена как cdecl, пос- кольку загрузочный код С всегда пытается вызвать главную процедуру (main) по соглашениям С. После компиляции программы с опцией -pвам может понадо- биться,чтобы некоторые идентификаторы сохранили регистр, в котором они были первоначально набраны, и ведущий знак под- черкивания, особенно если это идентификаторы С из другого файла. Это можно сделать, объявив этиидентификаторыкак cdecl. (Это также влияет на передачу параметров функциям). Как и pascal, модификатор cdecl специфичен для Turbo C+ +. Он используется с функциями и указателями функций. Этот- модификатор переопределяет директиву компилятора -p и позво- ляет вызывать такую функцию как правильную функцию С. Напри- мер, если вы компилируете предыдущую программус - 51 - установленной опцией -p, но желаете использовать printf, то нужно сделать следующее: extern cdecl printf(); putnums(int i, int j, int k); cdecl main() (* putnums(1,4,9); *) putnums(int i, int j, int k) (* printf("And the answers are: %d, %d, and %j\n",i,j,k); *) При компиляции такой программы с опцией -p все функции из библиотеки исполняющей системы должны иметь объявление cdecl. Если вы посмотрите файлы заголовка (такие как stdio.h), вы увидите, что с учетом этого каждая функция оп- ределена там как cdecl. Модификаторы указателей Turbo C++ имеет восемь модификаторов, влияющих на опе- рацию обращения поссылке, то есть на модификацию указателей в данные. Эти модификаторы: near, far, huge, _cs, _ds, _es, _seg и _ss. С позволяет выполнять компиляцию с использованием одной из нескольких моделей памяти. Используемая вами модель опре- деляет (помимо всего прочего) внутренний формат указателей. Например, при использованиималой данных small (tiny, small, medium)все указатели данных содержат 16-битовое смещение ре- гистра сегмента данных (DS). При использовании большой моде- ли данных (compact, large, huge)все указатели данных имеют длину 32 бита и содержат как адрес сегмента, так и смещение. Иногда, используя один размер модели данных, вам может понадобитьсяобъявить указатель, размер или формат которого отличен от текущегопо умолчанию.Это делаетсяс помощью моди- фикаторов указателей. Углубленное рассмотрение указателей near, far и huge см. на стр. 192 оригинала в главе 4, а описание нормализо- ванных указателей см. на стр. 193 оригинала. Кроме того, см. на стр. 199 оригинала обсуждение _cs, _ds, _es, _seg и _ss.

Страницы: 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

— 81 —

Округление всегда выполняется к нулю.
Операции типа сложения

Существует две операции типа сложения: + и -. Синтаксис
этих операций следующий:

выражение-типа-сложения:
выражение-типа-умножения
выражение-типа-сложения + выражение-типа-умножения
выражение-типа-сложения — выражение-типа-умножения

Операция сложения +

Допустимыми являются следующие типы операндов выражения
операнд1 + операнд2:

1. Операнд1 и операнд2 оба арифметического типа.

2. Операнд1 интегрального типа, а операнд2 является
указателем на объект.

3. Операнд2 интегрального типа, а операнд1 является
указателем на объект.

В первом случае выполняются стандартные арифметические
преобразования операндов, а результатом является их арифме-
тическая сумма. В случаях 2 и 3 применяются правила арифме-
тических действий с указателями. (Арифметические действия с
указателями рассматриваются на стр.57 оригинала).

Операция вычитания —

Допустимыми являются следующие типы операндов выражения
операнд1 — операнд2:

1. Операнд1 и операнд2 оба арифметического типа.

2. Оба операнда являются указателями на совместимые ти-
пы объектов. (Примечание: неквалифицированный тип type расс-
матривается как совместимый с квалифицированными типами
const type, volatile type и const volatile type.)

3. Операнд2 интегрального типа, а операнд1 является
указателем на объект.

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

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

Существует две операции поразрядного сдвига: >.
Синтаксис этих операций следующий:

выражение-типа-сдвига:
выражение-типа-сложения
выражение-типа-сдвига > выражение типа сдвига

Операция поразрядного сдвига влево > E2 операнды Е1 и Е2 должны иметь тип
int. С Е1 и Е2 выполняются обычные целочисленные действия, а
тип результата определяется операндом Е1. Если Е2 отрицате-
лен, либо по числу разрядов больше или равен Е1, то операция
неопределена.

Результатом операции E1 >> E2 является значение E1,
сдвинутое вправо на Е2 разрядов. Если Е1 имеет тип unsigned,

то при необходимости происходит его заполнение нулями слева.
Если же Е1 имеет тип signed, то заполнение слева выполняется
знаком (0 для положительных и 1 для отрицательных значений).
Такое расширение знакового бита гарантирует, что знак у Е1
>> E2 будет таким же, как и у E1. За исключением типов со
знаком, значение E1 >> E2 представляет собой целую часть
частного.

Операции отношения

Существует четыре операции отношения: < > =. Син-
таксис этих операций следующий:

выражение-отношения:
выражение-типа-сдвига
выражение-отношения < выражение-типа-сдвига выражение-отношения > выражение-типа-сдвига
выражение-отношения =выражение-типа-сдвига

Операция меньше чем < В выражении E1 < E2 операнды должны удовлетворять одно- му из следующего набора условий: 1. Оба значения Е1 и Е2 - арифметического типа. 2. Оба значения Е1 и Е2 являются указателями квалифици- рованных или неквалифицированных версий совместимых типов объектов. Определение квалифицированных имен дается на стр.108 оригинала. 3. Оба значения Е1 и Е2 являются указателями квалифици- рованных или неквалифицированных версий совместимых неполных типов. В случае 1 выполняются обычные арифметические преобра- зования. Результат E1 < E2 имеет тип int. Если значение E1 меньше значения E2, то результат равен 1 (истина); в против- - 83 - ном случае результат равен 0 (ложь). В случаях 2 и 3, где Е1 и Е2 являются указателями сов- местимых типов, результат операции E1 E2 дает 1 (истина), если значение Е1 больше значения Е2;в противном случае результат равен 0 (ложь), причем используются те же способы интерпретации арифметических сравнений и сравнений указателей, что опреде- лены для операции "больше чем". К операндам применимы те же правила и ограничения. Операция меньше или равно = E2 дает 1 (истина), если значение Е1 больше или равно значению Е2. В противном случае результат равен 0 (ложь), причем используются те же способы интерпретации арифметических сравнений и сравнений указате- лей, что определены для операции "меньше чем". К операндам применимы те же правила и ограничения. Операции типа равенства Существует две операции типа равенства: == и !=. Они проверяют условие равенства операндов арифметического типа и типа указателей, следуя при этом правилам, аналогичным тем, что действуют для операцийотношения. Отметим, однако, что == и != имеют более низкий приоритет выполнения, чем операции отношения , =. Кроме того, операции == и != позво- ляют выполнять проверку равенства указателей в таких случа- ях, где операции отношения неприменимы. Синтаксис этих опе- раций следующий: выражение-типа-равенства:

Страницы: 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

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