C++ CSS HTML Java JavaScript MySQL Oracle PERL PHP SQL Unix VBScript XHTML XML Сети
Справочное руководство. Выражения.
 
                  
                        7. Выражения

     Приоритет операций в выраженях такой же,  как и  порядок
главных подразделов   в этом разделе,  наибольший приоритет у
первого. Так  например, выражения, о которых говорится как об
операндах операции + (#7.4) - это те выражения, которые опре-
делены в ##7.1-7.4.  Внутри каждого подраздела операции имеют
одинаковый приоритет. В каждом подразделе для рассматриваемых
в нем операций определяется их левая или  правая  ассоциатив-
ность (порядок обработки операндов).  Приоритет и ассоциатив-
ность всех операций собран вместе  в  описании  грамматики  в
#14.

      побочные эффекты.   Порядок  возникновения
побочных эффектов неопределен.  Выражения,  включающие в себя
коммутативные и асссоциативные операции (*,  +, &, !, ^), мо-
гут быть реорганизованы произвольным образом,  даже при нали-
чии скобок; для задания определенного порядка вычисления  вы-
ражения необходимо использовать явную временную переменную.

     Обработка переполнения и контроль деления при вычислении
выражения машинно зависимы. В большинстве существующих реали-
заций С++ переполнение целого игнорируется; обработка деления
на 0 и всех исключительных ситуаций  с  числами  с  плавающей
точкой различаются  от машины к машине и обычно могут регули-
роваться библиотечными функциями.

     Кроме стандартного значения,   описанного  в  #7.2-7.15,
операции могут быть перегружены*,  то есть, могут быть заданы
их значения для случая их применения к  типам,   определяемым
пользователем, см. #7.16.

 --------------------
     * Этот термин применяется для описания  использования  в
языке одной и той же лексемы для обозначения различных проце-
дур; вид процедуры выбирается компилятором на  основании  до-
полнительной информации в виде числа и типа аргументов и т.п.
(прим.перев.)

                   7.1 Основные Выражения

     Основные выражения,  включающие в себя . , -> , индекси-
рование и вызовы функций, группируются слева направо.

   список_выражений:
       выражение
       список_выражений , выражение

   id:
       идентификатор
       имя_функции_операции
       typedef-имя :: идентификатор
       typedef-имя :: имя_функции_операции

   первичное_выражение:
       id
       :: идентификатор
       константа
       строка
       this
       ( выражение )
       первичное_выражение [ выражение ]
       первичное_выражение ( список_выражений opt )
       первичное_выражение . id
       первичное_выражение -> id

     Идентификатор есть первичное выражение, причем соответс-
твенно описанное (#8).  Имя_функции_операции есть идентифика-
тор со специальным значением, см. #7.16 и #8.5.1.

      скрыт (#4.1).

     Typedef-имя (#8.8)  ,  за которым следует ::, после чего
следует идентификатор, является первичным выражением. Typedef
-имя должно обозначать класс (#8.5),  и идентификатор  должен
обозначать член этого класса.  Его тип специфицируется описа-
нием идентификатора.  Typedef-имя может быть  скрыто  именем,
которое не   является именем типа.  В этом случае typedef-имя
все равно может быть найдено и его можно использовать.

     Константа является первичным выражением.  Ее тип  должен
быть int, long или double в зависимости от ее формы.

     Строка является  первичным выражением.  Ее тип - "массив
символов". Обычно он сразу же преобразуется в указатель на ее
первый символ (#6.7).

     Ключевое слово this является локальной переменной в теле
функции члена (см. #8.5) . Оно является указателем на объект,
для которого функция была вызвана.

     Выражение, заключенное  в круглые скобки,  является пер-
вичным выражением, чей тип и значение те же, что и у незаклю-
ченного в  скобки выражения.  Наличие скобок не влияет на то,
является выражение lvalue или нет.

     Первичное выражение,  за  которым  следует  выражение  в
квадратных скобках,  является первичным выражением. Интуитив-
ный смысл - индекс.  Обычно  первичное  выражение  имеет  тип
"указатель на  ...",  индексирующее выражение имеет тип int и
тип результата есть "...". Выражение Е1[Е2] идентично (по оп-
ределению) выражению  *((E1)+(E2)). Все тонкие места, необхо-
димые для понимания этой записи,  содержатся в  этом  разделе
вместе с   обсуждением в ## 7.1,  7.2 и 7.4,  соответственно,
идентификаторов, *  и + ; ниже, в #8.4.2 приводятся следствия
из этого.

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

     Каждый формальный параметр инициализируется  фактическим
параметром (#8.6). Выполняются стандартные (#6.6-8) и опреде-
ляемые пользователем преобразования (#8.5.6).  Функция  может
изменять значения своих формальных параметров, но эти измене-
ния не могут повлиять на значения фактических  параметров  за
исключением случая, когда формальный параметр имеет ссылочный
тип.

     Функция может быть описана  как  получающая  меньше  или
больше параметров,    чем  специфицировано в описании функции
(#8.4). Каждый  фактический параметр типа float, для которого
нет формального   параметра,  преобразуются к типу double; и,
как обычно,  имена массивов преобразуются к указателям. Поря-
док вычисления  параметров не определен языком; имейте в виду
различия между компиляторами.

     Допустимы рекурсивные вызовы любых функций.

     Первичное выражение,  после которого стоит точка, за ко-
торой следует   идентификатор (или идентификатор,  уточненный
typedef-именем с помощью операции ::)   является  выражением.
Первое выражение должно быть объектом класса, а идентификатор
должен именовать член этого класса. Значением является имено-
ванный член объекта, и оно является адресным, если первое вы-
ражение является адресным.  Следует отметить,  что "классовые
объекты" могут  быть структурами (#8.5.12)  или объединениями
(#8.5.13).

     Первичное выражение,  после которого стоит стрелка (  ->
), за которой следует идентификатор (или идентификатор, уточ-
ненный typedef-именем с помощью операции ::) является выраже-
нием. Первое выражение должно быть указателем на объект клас-
са, а  идентификатор  должен  именовать  член  этого  класса.
Значение является   адресом,  ссылающимся на именованный член
класса, на который указывает указательное выражение. Так, вы-
ражение E1->MOS есть то же,  что и (*E1).MOS. Классы обсужда-
ются в #8.5.

     Если первичное выражение дает значение  типа  "указатель
на ..." (см.  #8.4 and #8.6.3),  значением выражения был объ-
ект, обозначаемый ссылкой. Ссылку можно считать именем объек-
та, см. #8.6.3.

                    7.2 Унарные Операции

     Выражения с  унарными операциями группируют справа нале-
во:

   унарное_выражение:
       унарная_операция выражение
       выражение ++
       выражение --
       sizeof выражение
       sizeof ( имя_типа )
       ( имя_типа ) выражение
       простое_имя_типа ( список_выражений )
       new имя_типа инициализатор opt
       new ( имя_типа )
       delete выражение
       delete [ выражение ] выражение
   унарная_операция: одна из
       * & - ! ~ ++ --

     Унарная операция   *   означает   косвенное   обращение:
выражение должно быть указателем и результатом будет  lvalue,
ссылающееся на объект,  на который указывает выражение.  Если
выражение имеет тип "указатель на ...",   то  тип  результата
есть "...".

     Результатом унарной  операции  &  является  указатель на
объект, на  который ссылается операнд.  Операнд  должен  быть
lvalue. Если    выражение имеет тип "...",  то тип результата
есть "указатель на ...".

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

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

     Результатом операции логического отрицания ! является 1,
если значение операнда 0,  и 0,  если значение операнда не 0.
Результат имеет тип int.  Применима к любому  арифметическому
типу или к указателям.

     Операция ~ дает дополнение значения операнда до единицы.
Выполняются обычные арифметические  преобразования.   Операнд
должен иметь целочисленный тип.
                                           
                                           
                7.2.1 Увеличение и Уменьшение

     Операнд префиксного ++ получает приращение. Операнд дол-
жен быть адресным . Значением является новое значение операн-
да, но  оно не адресное.  Выражение ++x эквивалентно x+=1. По
поводу данных о преобразованиях см.  обсуждение операций сло-
жения (#7.4) и присваивания (#7.14).

     Операнд префиксного  --  уменьшается аналогично действию
префиксной операции ++.

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

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

                        7.2.2 sizeof

     Операция sizeof дает размер операнда в байтах.  (Байт не
определяется языком иначе, чем через значение sizeof. Однако,
во всех существующих реализациях байт есть пространтсво,  не-
обходимое для   хранения char.)  При применении к массиву ре-
зультатом является полное количество байтов в массиве. Размер
определяется из описаний объектов,  входящих в выражение. Се-
мантически это выражение является  беззнаковой  константой  и
может быть использовано в любом месте, где требуется констан-
та.

     Операцию sizeof можно также применять к  заключенному  в
скобки имени типа.  В этом случае она дает размер,  в байтах,
объекта указанного типа.

               7.2.3 Явное Преобразование Типа

      конструктором #8.5.5) влечет преобразование
значения выражения в названный тип. Чтобы записать преобразо-
вание в тип, не имеющий простого имени, имя_типа (#8.7) долж-
но быть заключено в скобки. Если имя типа заключено в скобки,
выражение заключать в скобки необязательно.  Такая запись на-
зывается приведением к типу.

     Указатель может быть явно преобразован к любому из цело-
численных типов, достаточно по величине для его хранения. То,
какой из int и long требуется,  является  машинно  зависимым.
Отобразующая функция   также  является машинно зависимой,  но
предполагается, что  она не содержит сюрпризов для того,  кто
знает структуру адресации в машине. Подробности для некоторых
конкретных машин были приведены в #2.6.

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

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

     Объект может  преобразовываться  в  объект класса только
если был описан соответствующий конструктор или операция пре-
образования (#8.5.6).

     Объект может  явно преобразовываться в ссылочный тип &x,
если указатель на этот объект может явно преобразовываться  в
x*.

                   7.2.4 Свободная Память

       new возвращает указатель  на  созданный  ей
объект. Когда  объект является массивом,  возвращается указа-
етль на его первый элемент. Например, и new int и new int[10]
возвращают int*.  Для объектов некоторых классов надо предос-
тавлять инициализатор (#8.6.2). Операция new (#7.2) для полу-
чения памяти вызывает функцию

   void* operator new (long);

     Параметр задает  требуемое  число  байтов.  Память будет
инициализирована. Если  operator new() не может найти требуе-
мое количество памяти, то она возвращает ноль.

     Операция delete  уничтожает объект,  созданный операцией
new. Ее  результат является void.  Операнд delete должен быть
указателем, возвращенным  new.  Результат применения delete к
указателю, который не был получен с помощью операции new. Од-
нако уничтожение с помощью delete указателя со значением ноль
безвредно.

     Чтобы освободить указанную память, операция delete вызы-
вает функцию

    void operator delete (void*);

   В форме

   delete [ выражение ] выражение

      см. #8.5.8.

               7.3 Мультипликативные Операции

     Мультипликативные операции  *,   /  и % группируют слева
направо. Выполняются обычные арифметические преобразования.

  мультипликативное_выражение:
      выражение * выражение
      выражение / выражение
      выражение % выражение

     Бинарная операция * определяет умножение. Операция * ас-
социативна и выражения с  несколькими  умножениями  на  одном
уровне могут быть реорганизованы компилятором.
     Бинарная операция / определяет деление.  При делении по-
ложительных целых округление осуществляется в сторону 0,   но
если какой-либо из операндов отрицателен, то форма округления
является машинно зависимой.  На всех  машинах,   охватываемых
данным руководством,  остаток имеет тот же знак,  что и дели-
мое. Всегда  истиинно,  что (a/b)*b + a%b равно a (если b  не
0).

     Бинарная операция  % дает остаток от деления первого вы-
ражения на второе.  Выполняются обычные арифметические преоб-
разования. Операнды   не должны быть числами с плавающей точ-
кой.

                   7.4 Аддитивные Операции

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

  аддитивное_выражение:
      выражение + выражение
      выражение - выражение

     Результатом операции  + является сумма операндов.  Можно
суммировать указатель на объект массива и значение целого ти-
па. Последнее во всех случаях преобразуется к смещению адреса
с помощью умножения его на длину объекта, на который указыва-
ет указатель.    Результатом является указатель того же типа,
что и исходный указатель, уазывающий на другой объект того же
массива и соответствующим образом смещенный от первоначально-
го объекта.  Так, если p есть указатель на объект массива, то
выражение p+1 есть указатель на следующий объект массива.

     Никакие другие комбинации типов для указателей не допус-
тимы.

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

      применяются те же преобразования,  что и к
сложению.

     Если вычитаются указатели на объекты одного типа, то ре-
зультат преобразуется  (посредством деления на длину объекта)
к целому,  представляющему собой число объектов,  разделяющих
объекты, указанные  указателями.  В засисимости от машины ре-
зультирующее целое может быть или типа int,  или  типа  long,
см. #2.6.  Вообще говоря, это преобразование будет давать не-
определенный результат кроме тех  случаев,   когда  указатели
указывают на объекты одного массива, поскольку указатели, да-
же на объекты одинакового типа, не обязательно различаются на
величину, кратную длине объекта.

                     7.5 Операции Сдвига

     Операции сдвига  <<  и >> группируют слева направо.  Обе
выполняют одно обычное арифметическое преобразование над сво-
ими операндами,  каждый из которых должен быть целым.  В этом
случае правый операнд преобразуется к типу int; тип результа-
та совпадает с типом левого операнда.  Результат неопределен,
если правый операнд отрицателен или больше  или  равен  длине
объекта в битах.

  сдвиговое_выражение:
      выражение << выражение
      выражение >> выражение

     Значением Е1  << Е2 является Е1 (рассматриваемое как би-
товое представление), сдвинутое влево на Е2 битов; освободив-
шиеся биты заполняются нулями. Значением Е1 >> Е2 является Е1
, сдвинутое  вправо на Е2 битовых позиций. Гарантируется, что
сдвиг вправо является логическим (заполнение нулями), если Е1
является unsigned; в противном случае он может быть арифмети-
чевким (заполнение копией знакового бита).

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

     Операции отношения (сравнения) группируют слева направо,
но этот факт не очень-то полезен:  a < b < c не означает  то,
чем кажется.

  выражение_отношения:
      выражение < выражение
      выражение > выражение
      выражение <= выражение
      выражение >= выражение

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

                   7.7 Операции Равенства

  выражение_равенства:
      выражение == выражение
      выражение != выражение

     <b == c<d
есть 1 всегда,  когда a<b и c<d имеют одинаковое истинностное
значение.)

     Указатель может сравниваться с 0.

                  7.8 Операция Побитовое И

  И-выражение:
      выражение & выражение

     & ассоциативна,  и выражения, содержащие &, мо-
гут реорганизовываться.    Выполняются обычные арифметические
преобразования; результатом является побитовая функция И опе-
рандов. Операция применяется только к целым операндам.

           7.9 Операция Побитовое Исключающее ИЛИ

  исключающее_ИЛИ_выражение:
      выражение ^ выражение

        Операция применяется только к целым
операндам.

           7.10 Операция Побитовое Включающее ИЛИ

     включающее_ИЛИ_выражение:
          выражение ! выражение

       Операция применяется  только  к  целым
операндам.

                 7.11 Операция Логическое И

  логическое_И_выражение:
      выражение && выражение

     Операция && группирует слева направо.  Она возвращает 1,
если оба операнда ненулевые, и 0 в противном случае. В проти-
воположность операции & операция  &&  гарантирует  вычисление
слева направо; более того, второй операнд не вычисляется, ес-
ли первый операнд есть 0.

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

                7.12 Операция Логическое ИЛИ

  логическое_ИЛИ_выражение:
      выражение !! выражение

     Операция !! группирует слева направо.  Она возвращает 1,
если хотя бы один из ее операндов ненуелвой,  и 0 в противном
случае. В противоположность операции ! операция !! гарантиру-
ет вычисление слева направо; более того,  второй  операнд  не
вычисляется, если первый операнд не есть 0.

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

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

  условное_выражение:
      выражение ? выражение : выражение

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

                 7.14 Операции Присваивания

     Есть много операций присваивания,  все группируют  слева
направо. Все в качестве левого операнда требуют lvalue, и тип
выражения присваивания тот же,  что и у его левого  операнда.
Это lvalue не может ссылаться на константу (имя массива,  имя
функции или const). Значением является значение, хранящееся в
левом операнде просле выполнения присваивания.

  выражение_присваивания:

      выражение операция_присваивания выражение

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

      = += -= *= /= %= >>= <<= &= ~= !=

      правый операнд преобразуется к типу
левого. Если   аргумент в левой части имеет указательный тип,
аргумент в правой части должен быть того же  типа  или  типа,
который может быть преобразован к нему, см. #6.7. Оба операн-
да могут быть объектами одного класса.   Могут  присваиваться
объекты некоторых производных классов, см. #8.5.3.

     Присваивание объекту  типа  "указатель  на ..." выполнит
присваивание объекту, денотируемому ссылкой.

     Выполнение выражения вида e1 op=  e2  можно  представить
себе как   эквивалентное  e1  = e1 op (e2); но e1 вычисляется
только один раз.  В += и -= левый операнд может быть указате-
лем, и  в этом случае (целочисленный) правый операнд преобра-
зуется так,  как объяснялось в #7.4; все правые операнды и не
являющиеся указателями левые должны иметь арифметический тип.

                    7.15 Операция Запятая

  запятая_выражение:
      выражение , выражение

     Пара выражений,  разделенных запятой,  вычисляется слева
направо, значение  левого выражения теряется.  Тип и значение
результата являются типом и значением правого операнда.   Эта
операция группирует слева направо.  В контексте,  где запятая
имеет специальное значение, как например в списке фактических
параметров функции (#7.1)  и в списке инициализаторов (#8.6),
операция запятая, как она описана в этом разделе, может появ-
ляться только в скобках; например,

  f (a,(t=3,t+2),c)

  имеет три параметра, вторым из которых является значение 5.

                 7.16 Перегруженные Операции

      смысл операций при применении  их  к
неклассовым объектам.   Предопределенный смысл операций = и &
(унарной) при применении их к объектам классов может быть из-
менен.

      присваивание, в случае применения к основным
типам требуют, чтобы операнд был lvalue; это не требуется для
операций, описанных для классовых типов.

                   7.16.1 Унарные Операции

     Унарная операция, префиксная или постфиксная, может быть
определена или с помощью функции члена (см. #8.5.4), не полу-
чающей параметров, или с помощью функции друга (см. #8.5.10),
получающей один параметр, но не двумя способами одновременно.
Так, для  любой унарной операции @, x@ и @x могут интерпрети-
роваться как x.операция@()  или операция@(x).  При перегрузке
операций ++ и -- невозможно различить префиксное и  постфикс-
ное использование.

                  7.16.2 Бинарные Операции

     Бинарная операция  может  быть  определена или с помощью
функции члена (см.  #8.5.4),  получающей один параметр, или с
помощью функции друга (см. #8.5.9), получающей два параметра,
но не двумя способами одновременно.  Так,  для любой бинарной
операции @, x@y может быть проинтерпретировано как x.operator
@(y) или operator@(x,y).

                   7.16.3 Особые Операции

  Вызов функции
  первичное_выражение ( список_выражений opt )

и индексирование

  первичное_выражение [ выражение ]

     считаются бинарными  операциями.   Именами  определяющей
функции являются соответсвенно operator() и operator[]. Обра-
щение x(arg) интерпретируется как x.operator()(arg) для клас-
сового объекта x. Индексирование x[y] интерпретируется как x.
operator[](y).

[Назад] [Содержание] [Вперед]

Главная