46019 (665326), страница 13
Текст из файла (страница 13)
typedef enum days DAYS;
DAYS *daysptr; int i = tues; anyday = mon; // так можно
*daysptr = anyday; // так можно
mon = tues; // неверно: mon - это константа
Теги перечислимых типов разделяют пространство имен с тегами структур и объединений. Нумераторы разделяют пространство имен с обычными идентификаторами переменных:
int mon = 11;
(*
enum days (* sun, mon, tues, wed, thur, fri, sat *) anyday;
/* нумератор mon скрывает внешнее объявление int mon */ struct days (* int i, j;); // неверно: дублируется тег days
double sat; // неверно: переопределение sat
*)
mon = 12; // снова в контексте int mon
C++ В С++ нумераторы, объявленные в пределах класса,имеют контекст этого класса.
Выражения
В таблице 1.19 показано, каким образом комбинируются идентификаторы и операции для составления грамматически верных "фраз".
Выражением называется последовательность операций, операндов и пунктуаторов, задающих определенное вычисление. Формальный синтаксис, показанный в таблице 1.19, обозначает, что выражения определяются рекурсивно: под-выражения могут быть вложены без формальных ограничений. (Однако, если компилятор не сможет обработать какое-либо слишком сложное выражение, то будет выдано сообщение об ошибке).
Выражения Turbo C++ Таблица 1.19
первичное-выражение:
литерал
псевдо-переменная
(выражение)
this (только С++)
:: идентификатор (только С++)
:: имя-функции-операции (только С++)
имя
литерал:
целочисленная-константа
символьная-константа
константа-с-плавающей-точкой
строка
имя:
идентификатор:
имя-функции-операции (только С++)
имя-функции-преобразования (только С++)
квалифицированное-имя (только С++)
квалифицированное-имя: (только С++)
имя-класса :: идентификатор
имя-класса :: имя-функции-операции
имя-класса :: имя-функции-преобразования
имя-класса :: имя-класса
имя-класса :: - имя-класса
постфиксное-выражение:
первичное-выражение
постфиксное-выражение[выражение]
постфиксное-выражение ()
постфиксное-выражение () (только С++) постфиксное-выражение . имя постфиксное-выражение -> имя постфиксное-выражение ++ постфиксное-выражение --
список-выражений:
выражение-присваивания
список-выражений , выражение-присваивания
унарное-выражение:
постфиксное-выражение
++ унарное-выражение
-- унарное-выражение
унарная-операция выражение-приведения
sizeof унарное-выражение
sizeof (имя-типа)
выражение-распределения (только С++)
выражение-отмены-распределения (только С++)
унарная-операция: одно из
& * + - тильда !
выражение-распределения: (только С++)
new имя-ограниченного-типа <инициализатор
new имя-типа
местоположение: (только С++)
(список-выражений)
имя-ограниченного-типа: (только С++)
спецификатор-типа
декларатор-ограничения: (только С++)
операция-указателя
декларатор-ограничения []
выражение-отмены-распределения: (только С++)
delete выражение-приведения
delete [выражение] выражение-приведения
выражение-приведения:
унарное-выражение
(имя-типа) выражение-приведения
выражение-типа-ссылки:
выражение-приведения
выражение-типа-ссылки .* выражение-приведения (только С ++) выражение-типа-ссылки -> выражение-приведения (только С+ +)
выражение-типа-умножения:
выражение-типа-ссылки
выражение-типа-умножения * выражение-типа-ссылки
выражение-типа-умножения / выражение-типа-ссылки
выражение-типа-умножения % выражение-типа-ссылки
выражение-типа-сложения:
выражение-типа-умножения
выражение-типа-сложения + выражение-типа-умножения
выражение-типа-сложения - выражение-типа-умножения
выражение-типа-сдвига:
выражение-типа-сложения
выражение-типа-сдвига << выражение-типа-сложения
выражение-типа-сдвига >> выражение-типа-сложения
выражение-отношения:
выражение-типа-сдвига
выражение-отношения < выражение-типа-сдвига
выражение-отношения > выражение-типа-сдвига
выражение-отношения <= выражение-типа-сдвига
выражение-отношения >= выражение-типа-сдвига
выражение-типа-равенства:
выражение-отношения
выражение-типа-равенства = выражение-отношения
выражение-типа-равенства != выражение-отношения
выражение-И:
выражение-типа-равенства
выражение-И & выражение-типа-равенства
выражение-исключающее-ИЛИ:
выражение-И
выражение-исключающее-ИЛИ выражение-логическое-И
выражение-включающее-ИЛИ:
выражение-исключающее-ИЛИ
выражение-включающее-ИЛИ \! выражение-исключающее-ИЛИ
выражение-логическое-И:
выражение-включающее-ИЛИ
выражение-логическое-И && выражение-включающее-ИЛИ
выражение-логическое-ИЛИ:
выражение-логическое-И
выражение-логическое-ИЛИ !! выражение-логическое-И
условное-выражение:
выражение-логическое-ИЛИ
выражение-логическое-ИЛИ ? выражение : условное-выражение
выражение-присвоения:
условное-выражение
унарное-выражение операция-присвоения выражение-присвоения
операция-присвоения: одно из
= *= /=%= += -=
<<= ??= &=^= \!=
выражение:
выражение-присвоения
выражение, выражение-присвоения
выражение-типа-константы:
условное-выражение
Стандартные преобразования подробно рассматриваются на стр.42 оригинала, в таблице 1.15.
Вычисление выражений выполняется по определенным правилам преобразования, группировки, ассоциативности и приоритета, которые зависят от используемых в выражениях операций, наличию круглых скобок и типов данных операндов. Способ группировки операндов и подвыражений не обязательно определяет фактический порядок вычисления выражений в Turbo C++ (см. "Последовательность вычислений" на стр. 76 оригинала.)
Выражения могутдаватьв результате именующие выражения (lvalue), значения переменных (rvalue), либо не давать никаких выражений вообще. Не зависимо от того, является ли результатом выражения некоторое значение, выражение может иметь побочный эффект.
Грамматические правила, приведенные в таблице 1.19, на стр. 74 оригинала, полностью определяют приоритеты и ассоциативность операций. Кратко эта информация сведена в таблице
1.20. Существует пятнадцать категорийприоритетов, некоторые из которых содержат только одну операцию. Операции, относящиеся к одной и той же категории, имеют одинаковый приоритет выполнения. Каждой категории соответствует собственное правило ассоциативности: слева-направо или справа-налево. При отсутствии в выражении круглых скобок эти правила используются для разрешения группировки выражения с операциями равного приоритета.
Ассоциативность и приоритеты операций Turbo C++ Tаблица 1.20
Операции Ассоциативность
() [] -> :: . Слева-направо
! тильда - ++ -- & * Справа-налево
sizeof new delete .* ->* / % Слева-направо
+ - Слева-направо
<> Слева-направо
< >= Слева-направо
& Слева-направо
^ Слева-направо
\! Слева-направо
&& Слева-направо
\!\! Слева-направо
?:условное выражение Справа-налево
= += /= %= += -= Справа-налево
&= ^= \!= , Слева-направо
Приоритеты обозначаютсяпоследовательностью расположения в данной таблице. Первый элемент таблицы имеет наивысший приоритет.
Выражения и Turbo C++
С++ позволяет перегрузку некоторых стандартных операций С, как описано начиная со стр.125 оригинала. Перегруженной называется такая операция, которая применительно к выражениям типа класса ведет себя некоторым специальным образом. Например, оператор отношения == может быть определен в классе complex для проверки равенства двух комплексныхчисел, причем действие его для типов данных других классов остается прежним. Перегруженный оператор реализуется как функция; эта функция определяет тип операнда, именующее выражение (lvalue) и последовательность вычислений, устанавливаемая при использовании перегруженного оператора. Однако, перегрузка не может изменять приоритеты операций. Аналогичным образом, С++ позволяет выполнять определяемые пользователем преобразования между объектами класса и фундаментальными типами. Учтите, что некоторые правила относительно операций и преобразований, обсуждаемые в данном разделе, неприменимы к выражениям в С++.
Последовательность вычислений
Последовательность вычисления операндов в выражениях Turbo C++ не определена, если иное явно не задано операцией. Компилятор пытается реорганизовать выражение таким образом, чтобы улучшить качество генерируемого кода. Следовательно, необходима осторожностьпри работе с выражениями, в которых значение модифицируется более одного раза. В целом,следует избегать создания выражений, которые одновременно и модифицируют, и используют значение одного и того же объекта. Рассмотрим выражение
i = v[i++]; // i неопределено
Значение i зависит от того, выполняется ли инкрементирование до или после присвоения. Аналогичным образом,
int total = 0;
sum = [total = 3] + (++total);// sum = 4 или sum = 7 ??
имеет неоднозначность идентификаторов sum и total. Решение состоит в том, чтобы упростить выражение при помощи временной переменной:
int temp, temp = 0;
temp = ++total;
sum = (total = 3) + temp;
Когда синтаксиспринудительно устанавливает последовательность вычисления операндов, то множественные вычисления в одной конструкции не содержат опасности неоднозначности:
sum = (i = 3, i++, i++); // так можно: sum = 4, i = 5
Каждое под-выражение или выражение с запятыми вычисляется слева-направо, и все выражение в целом вычисляется понаправлению к самому правому значению.
Turbo C++ перегруппирует выражения, реорганизовывая ассоциативные и коммутативные операции независимо от наличия круглых скобок, с тем, чтобы получить эффективно компилируемое выражение; реорганизация выражения ни в коем случае не влияет на результатвычисления выражения.
Круглые скобки можно использовать для того, чтобы принудительно задать порядок вычислений в выражении. Например, если имеются переменные a, b, c и f, то выражение f=a+(b+c) вызывает сначала вычисление (b+c), а затем уже сложение результата с a.
Ошибки и переполнения
Во время вычисления выражения Turbo C++ может встретить многие проблематичные ситуации, как то деление на ноль или получение значений с плавающей точкой, выходящих за пределы допустимого диапазона. Переполнение целочисленных значений игнорируется (С использует арифметические действия по модулю 2 в n-разрядных регистрах), однако ошибки, обнаруживаемые математическими библиотечными функциями, могут обрабатываться стандартными или определяемыми пользователем подпрограммами. См. matherr и signal в Справочнике по Библиотеке.
- 76 -
Семантика операций
Описанные здесь операции Turbo C++ являются операциями стандарта ANSI C.
Если операции не перегружены, то следующая информация действительна как для С, так и для С++. В С++ вы можете перегрузить все эти операции, за исключением операции . (операция задания компонента) и ?: (условная операция) (также не могут быть перегружены операции С++ :: и .*).
Если операция перегружена, то приводимые здесь сведениядля нее недействительны.Таблица 1.19 на стр.74 оригинала приводит синтаксис для всех операций и выражений с операциями.
Постфиксные и префиксные операции
Шесть постфиксных операций [] () . -> ++и -- используются для построения постфиксных выражений, показанных в таблице синтаксиса выражений (таблица 1.19). Операции инкремента и декремента (++ и --) также являются префиксными и унарными операциями;они обсуждаются, начиная со стр.79 оригинала.
Операция индексации массива [] --------------------------
В выражении
постфиксное-выражение [выражение]
в С, но не обязательно в С++, выражение выраж1[выраж2] определяется как
*((выраж1) + (выраж2))
где либо выраж1 это указатель, а выраж2 это целочисленное значение, либо выраж1 это это целочисленное значение, а выраж1 это указатель. (Каждый из пунктуаторов [], * и + может быть перегружен в С++).
Операция вызова функции ()
Выражение
постфиксное-выражение()
представляет собой вызов функции, задаваемой постфиксным выражением. Список-аргументов-выражения - это разделяемый запятой список выражения любого типа, задающий фактические (или действительные) аргументы функции. Значение самого выражения вызова функции, если оно вообще имеет место, определяется оператором возврата в определении функции. См. "Вызовы функций и преобразования аргументов" на стр.63 оригинала, где приводится более поробное изложение вызова функций.
Операция задания компонента структуры/объединения . (точка)
В выражении
постфиксное-выражение . идетификатор
постфиксное-выражениедолжно иметь тип структуры или объединения; идентификатор должен являться именем компонента данной структуры или объединения. Выражение обозначает объект - компонент структуры или объединения. Значением данного выражения будет являться значение выбранного таким образом компонента; оно будет являться именующим выражением (lvalue) в том и только том случае, если именующим выражением является само постфиксное выражение. Подробное описание использования операций . и -> дается на стр.66 оригинала.