9.4 Оператор While
Оператор while имеет вид
while ( выражение ) оператор
Выполнение подоператора повторяется, пока значение выржения остается ненулевым. Проверка выполняется перед каждым выполнением оператора. Выражение обрабатывается как в услоном операторе (#9.3).
while ( выражение ) оператор
Выполнение подоператора повторяется, пока значение выржения остается ненулевым. Проверка выполняется перед каждым выполнением оператора. Выражение обрабатывается как в услоном операторе (#9.3).
9.5 Оператор Do
Оператор do имеет вид
do оператор while ( выражение ) ;
Выполнение подоператора повторяется до тех пор, пока значение остается не нулем. Проверка выполняется после каждго выполнения оператора. Выражение обрабатывается как в уловном операторе (#9.3).
do оператор while ( выражение ) ;
Выполнение подоператора повторяется до тех пор, пока значение остается не нулем. Проверка выполняется после каждго выполнения оператора. Выражение обрабатывается как в уловном операторе (#9.3).
9.6 Оператор For
Оператор for имеет вид
for (оператор_1 выражение_1 opt; выражение_2 opt) оператор_2
Этот оператор эквивалентен следующему:
оператор_1 while ( выражение_1 ) (* оператор_2 выражение_2 ; *)
за исключением того, что continue в операторе_2 будет выполнять выражение_2 перед выполнением выражения_1. Первый оператор, таким образом, задает инициализацию цикла; первое выражение задает выполняемую перед каждой итерацией проверку, по которой производится выход из цикла, если выражение станвится нулем; второе выражение часто задает приращение, выпоняемое после каждой итерации.
Каждое или оба выражения могут быть опущены. Отсутствие выражения_1 делает подразумеваемое while-предложение эквивлентым while(1). Заметьте, что если оператор_2 является опсанием, то область видимости описанного имени распространяеся до конца блока, охватывающего оператор for.
for (оператор_1 выражение_1 opt; выражение_2 opt) оператор_2
Этот оператор эквивалентен следующему:
оператор_1 while ( выражение_1 ) (* оператор_2 выражение_2 ; *)
за исключением того, что continue в операторе_2 будет выполнять выражение_2 перед выполнением выражения_1. Первый оператор, таким образом, задает инициализацию цикла; первое выражение задает выполняемую перед каждой итерацией проверку, по которой производится выход из цикла, если выражение станвится нулем; второе выражение часто задает приращение, выпоняемое после каждой итерации.
Каждое или оба выражения могут быть опущены. Отсутствие выражения_1 делает подразумеваемое while-предложение эквивлентым while(1). Заметьте, что если оператор_2 является опсанием, то область видимости описанного имени распространяеся до конца блока, охватывающего оператор for.
9.7 Оператор Switch
Оператор switch вызывает передачу управления на один из нескольких операторов в зависимости от значения выражения. Он имеет вид
switch ( выражение ) оператор
Выражение должно быть арифметичского или указательного типа. Любой оператор внутри оператора может быть помечен оной или более меток case следующим образом:
case константное_выражение :
где константное выражение должно иметь тот же тип что и выражение-переключатель; производятся обычные арифметические преобразования. В одном операторе switch никакие две констаты, помеченные case, не могут иметь одинаковое значение. Константные выражения определяются в #12.
Также может быть не более чем одна метка вида
default :
Когда выполнен оператор switch, проведено вычисление его выражения и сравнение его с каждой case константой. Если одна из констант равна значению выражения, то управление передаеся на выражение, следующее за подошедшей меткой case. Если никакая case константа не соответствует выражению, и есть метка default, то управление передается на выражение, которму она предшествует. Если нет соответсвующих вариантов case и default отсутствует, то никакой из операторов в операторе switch не выполняется.
Метки case и default сами по себе не изменяют поток уравления, который после задерки идет дальше, перескакивая чрез эти метки. Для выхода из switch см. break, #9.8.
Обычно зависящий от switch оператор является составным. В голове этого оператора могут стоять описания, но инициалзации автоматических и регистровых переменных являются безрзультатными.
switch ( выражение ) оператор
Выражение должно быть арифметичского или указательного типа. Любой оператор внутри оператора может быть помечен оной или более меток case следующим образом:
case константное_выражение :
где константное выражение должно иметь тот же тип что и выражение-переключатель; производятся обычные арифметические преобразования. В одном операторе switch никакие две констаты, помеченные case, не могут иметь одинаковое значение. Константные выражения определяются в #12.
Также может быть не более чем одна метка вида
default :
Когда выполнен оператор switch, проведено вычисление его выражения и сравнение его с каждой case константой. Если одна из констант равна значению выражения, то управление передаеся на выражение, следующее за подошедшей меткой case. Если никакая case константа не соответствует выражению, и есть метка default, то управление передается на выражение, которму она предшествует. Если нет соответсвующих вариантов case и default отсутствует, то никакой из операторов в операторе switch не выполняется.
Метки case и default сами по себе не изменяют поток уравления, который после задерки идет дальше, перескакивая чрез эти метки. Для выхода из switch см. break, #9.8.
Обычно зависящий от switch оператор является составным. В голове этого оператора могут стоять описания, но инициалзации автоматических и регистровых переменных являются безрзультатными.
9.8 Оператор Break
Оператор
break ;
вызывает завершение выполнения наименьшего охватывающего оператора while, do, for или switch; управление передается на
оператор, следующий за завершенным.
break ;
вызывает завершение выполнения наименьшего охватывающего оператора while, do, for или switch; управление передается на
оператор, следующий за завершенным.
9.9 Оператор Continue
Оператор
continue ;
вызывает передачу управления на управляющую продолжением цикла часть наименьшего охватывающего оператора while, do или for; то есть на конец петли цикла. Точнее, в каждом из оперторов
while (...) (* do (* for (...) (* ... ... ... contin: ; contin: ; contin: ; *) *) while (...); *)
continue эквивалентно goto contin. (За contin: идет путой оператор, #9.13.)
continue ;
вызывает передачу управления на управляющую продолжением цикла часть наименьшего охватывающего оператора while, do или for; то есть на конец петли цикла. Точнее, в каждом из оперторов
while (...) (* do (* for (...) (* ... ... ... contin: ; contin: ; contin: ; *) *) while (...); *)
continue эквивалентно goto contin. (За contin: идет путой оператор, #9.13.)
9.10 Оператор Return
Возврат из функции в вызывающеую программу осуществляеся с помощью оператора return, имеющего один из двух видов:
return ; return выражение ;
Первый может использоваться только в функциях, не возвращающих значения, т.е. в функциях с типом возвращаемого значения void. Вторая форма может использоваться только в функциях, возвращающих значение; значение выражения возвращется тому, кто вызывал функцию. Если необходимо, то выражение преобразуется, как это делается при инициализации, к типу функции, в которой оно появилось. Обход конца функции эквивлентен возврату return без возвращаемого значения.
return ; return выражение ;
Первый может использоваться только в функциях, не возвращающих значения, т.е. в функциях с типом возвращаемого значения void. Вторая форма может использоваться только в функциях, возвращающих значение; значение выражения возвращется тому, кто вызывал функцию. Если необходимо, то выражение преобразуется, как это делается при инициализации, к типу функции, в которой оно появилось. Обход конца функции эквивлентен возврату return без возвращаемого значения.
9.11 Оператор Goto
Можно осуществлять безусловную передачу упраления с пмощью оператора
goto идентификатор ;
Идентификатор должен быть меткой (#9.12), расположенной в текущей функции. Невозможно передать управление в обход описания с инициализатором (явным или неявным) никак, кроме передачи управления в обход внутреннего блока без захода в него.
goto идентификатор ;
Идентификатор должен быть меткой (#9.12), расположенной в текущей функции. Невозможно передать управление в обход описания с инициализатором (явным или неявным) никак, кроме передачи управления в обход внутреннего блока без захода в него.
9.12 Помеченные Операторы
Перед любым оператором может стоять метка, имеющий вид
идентификатор :
которая служит для описания идентификатора как метки. Метка используется только как объект перехода для goto. Оластью видимости метки является текущая функция, исключая лбой подблок, в котором был переописан этот же идентификатор. См. #4.1.
идентификатор :
которая служит для описания идентификатора как метки. Метка используется только как объект перехода для goto. Оластью видимости метки является текущая функция, исключая лбой подблок, в котором был переописан этот же идентификатор. См. #4.1.
9.13 Пустой Оператор
Пустой оператор имеет вид
;
Пустой оператор используется для помещения метки непоредственно перед *) составного оператора или того, чтобы снабдить такие операторы, как while, пустым телом.
;
Пустой оператор используется для помещения метки непоредственно перед *) составного оператора или того, чтобы снабдить такие операторы, как while, пустым телом.
9.14 Оператор Описание
Оператор описание используется для введения нового идетификатора в блоке; он имеет вид
Оператор_описание: описание
Если введенный описанием идентификатор был описан ранее во внешнем блоке, внешнее описание становится скрытым на пртяжении блока, после чего оно вновь всупает в силу.
Каждая инициализация auto и register переменных произвдится каждый раз, когда выполняется их оператор_описание. Можно передавать управление в блок, но не таким путем, котрый приводит к невыполнению инициализаций, см. #9.11. Иницилизации переменных класса памяти static (#4.4) производятся только один раз, когда программа начинает выполняться. 10. Определения Функций
Программа состоит из последовательности описаний. Код (текст программы) функции может быть задан только вне всех блоков и внутри описаний классов. Определения функций имеют вид
определение_функции: спецификаторы_описания opt описатель_функции инициализатор_базового opt тело_функции
Спецификаторы_описания register, auto, typedef не могут использоваться внутри описания класса (#8.5), а friend и virtual могут использоваться только там. Описатель функции – это описатель «функции, возвращающей ...» (#8.4).Формальные параметры находятся в области видимости самого внешнего блока тела_функции. Описатели функции имеют вид
описатель_функции:
описатель ( список_описаний_параметров )
Если параметр специфицирован как register, то соответтвующий фактический параметр будет по возможности копироватся в регистр на входе в функцию. Если для параметра специфцировано константное выражение в качестве инициализатора, то это значение используется как значение параметра по умолчнию.
Тело функции имеет вид
тело_функции: составной_оператор
Вот простой пример полного определения функции:
int max(int a, int b, int c) (* int m = (a « b) ? a : b; return (m » c) ? m : c; *)
Здесь int – это спецификатор_типа; max(int a, int b, int c) – это описатель_функции; (* ... *) – это тело_функции.
Поскольку в контексте выражения имя моссива (в особености, как фактического параметра) принимается как означающее указатель на первый элемент массива, описания формальных праметров, которые описаны как «массив из ...», корректируются так, чтобы читались как «указатель на ...».
В определении конструктора могут быть заданы инициализторы для базового класса и для членов. Это главным образом полезно для объектов класса, констант и ссылок, где семантика инициализации и присваивания различаются. Инициализатор_базвого имеет вид
инициализатор_базового: : список_инициализаторов_членов
список_инициализаторов_членов: инициализатор_члена инициализатор_члена , список_инициализаторов_членов
инициализатор_члена: идентификатор opt ( список_параметров opt )
Если в инициализаторе_члена дан идентификатор, то список параметров используется для инициализации названного члена; если нет, то список параметров используется для базового класса. Например:
struct base (* base(int); ... *);
struct derived : base (* derived(int); base b; const c;
*);
derived::derived(int a) : (a+1), b(a+2), c(a+3) (* /* ... */ *)
derived d(10);
Сначала конструктор базового класса вызывается для обекта d с параметром 11, затем вызывается конструктор для члна b с параметром 12 и конструктор для члена c с параметром 13. Затем выполняется тело derived::derived() (см. #8.5.5). Порядок, в котором вызываются конструкторы для членов, не утановлен. Если базовый класс имеет конструктор, который можно вызывать без параметров, не надо давать никакой список парметров. Если класс члена имеет конструктор, который можно взывать без параметров, для этого члена не надо давать никакой список параметров.
Оператор_описание: описание
Если введенный описанием идентификатор был описан ранее во внешнем блоке, внешнее описание становится скрытым на пртяжении блока, после чего оно вновь всупает в силу.
Каждая инициализация auto и register переменных произвдится каждый раз, когда выполняется их оператор_описание. Можно передавать управление в блок, но не таким путем, котрый приводит к невыполнению инициализаций, см. #9.11. Иницилизации переменных класса памяти static (#4.4) производятся только один раз, когда программа начинает выполняться. 10. Определения Функций
Программа состоит из последовательности описаний. Код (текст программы) функции может быть задан только вне всех блоков и внутри описаний классов. Определения функций имеют вид
определение_функции: спецификаторы_описания opt описатель_функции инициализатор_базового opt тело_функции
Спецификаторы_описания register, auto, typedef не могут использоваться внутри описания класса (#8.5), а friend и virtual могут использоваться только там. Описатель функции – это описатель «функции, возвращающей ...» (#8.4).Формальные параметры находятся в области видимости самого внешнего блока тела_функции. Описатели функции имеют вид
описатель_функции:
описатель ( список_описаний_параметров )
Если параметр специфицирован как register, то соответтвующий фактический параметр будет по возможности копироватся в регистр на входе в функцию. Если для параметра специфцировано константное выражение в качестве инициализатора, то это значение используется как значение параметра по умолчнию.
Тело функции имеет вид
тело_функции: составной_оператор
Вот простой пример полного определения функции:
int max(int a, int b, int c) (* int m = (a « b) ? a : b; return (m » c) ? m : c; *)
Здесь int – это спецификатор_типа; max(int a, int b, int c) – это описатель_функции; (* ... *) – это тело_функции.
Поскольку в контексте выражения имя моссива (в особености, как фактического параметра) принимается как означающее указатель на первый элемент массива, описания формальных праметров, которые описаны как «массив из ...», корректируются так, чтобы читались как «указатель на ...».
В определении конструктора могут быть заданы инициализторы для базового класса и для членов. Это главным образом полезно для объектов класса, констант и ссылок, где семантика инициализации и присваивания различаются. Инициализатор_базвого имеет вид
инициализатор_базового: : список_инициализаторов_членов
список_инициализаторов_членов: инициализатор_члена инициализатор_члена , список_инициализаторов_членов
инициализатор_члена: идентификатор opt ( список_параметров opt )
Если в инициализаторе_члена дан идентификатор, то список параметров используется для инициализации названного члена; если нет, то список параметров используется для базового класса. Например:
struct base (* base(int); ... *);
struct derived : base (* derived(int); base b; const c;
*);
derived::derived(int a) : (a+1), b(a+2), c(a+3) (* /* ... */ *)
derived d(10);
Сначала конструктор базового класса вызывается для обекта d с параметром 11, затем вызывается конструктор для члна b с параметром 12 и конструктор для члена c с параметром 13. Затем выполняется тело derived::derived() (см. #8.5.5). Порядок, в котором вызываются конструкторы для членов, не утановлен. Если базовый класс имеет конструктор, который можно вызывать без параметров, не надо давать никакой список парметров. Если класс члена имеет конструктор, который можно взывать без параметров, для этого члена не надо давать никакой список параметров.
11. Командные Строки Компилятора
Компилятор содержит препроцессор, способный выполнять макроподстановки, условную компиляцию и включение именованных файлов. Строки, начинающиеся с #, относятся к препроцессору. Эти строки имеют независимый от остального языка синтаксис; они могут появляться в любом месте и оказывать влияние, котрое распространяется (независимо от области видимости) до конца файла исходной программы.
Учтите, что определения const и inline дают альтернативы для большинства использований #define.
Учтите, что определения const и inline дают альтернативы для большинства использований #define.
11.1 Замена Лексем
Командная строка компилятора вида
#define идентификатор строка_лексем вызывает замену препроцессором последующих вхождений идентификатора, заданного строкой символов. Точка с запятой внутри (или в конце) строки символов является частью этой строки.
Строка вида
#define идентификатор( идентификатор , ... , идентификатор) строка_лексем
где нет пробела между первым идентификатором и (, явлется макроопределением с параметрами. Последующие вхождения первого идентификатора с идущими за ним (, последователностью символов, разграниченной запятыми, и ), заменяются строкой символов, заданной в определении. Каждое местоположние идентификатора, замеченного в списке параметров определния, заменяется соответствующей строкой из вызова. Фактичекими параметрами вызова являются строки символов, разделенные запятыми; однако запятые в строке, заключенной в кавычки, или в круглых скобках не являются разделителями параметров. Число формальных и фактических параметров должно совпадать. Строки и символьные константы в символьной строке сканируются в писках формальных параметров, но строки и символьные константы в остальной программе не сканируются в поисках определенных
(с помощью define) идентификаторов.
В обоих случаях строка замещения еще раз сканируется в поисках других определнных идентификаторов. В обоих случаях длинное определение может быть продолжено на другой строке с помощью записи \ в конце продолжаемой строки.
Командная строка вида
#undef идентификатор
влечет отмену препроцессорного определения идентификатра.
#define идентификатор строка_лексем вызывает замену препроцессором последующих вхождений идентификатора, заданного строкой символов. Точка с запятой внутри (или в конце) строки символов является частью этой строки.
Строка вида
#define идентификатор( идентификатор , ... , идентификатор) строка_лексем
где нет пробела между первым идентификатором и (, явлется макроопределением с параметрами. Последующие вхождения первого идентификатора с идущими за ним (, последователностью символов, разграниченной запятыми, и ), заменяются строкой символов, заданной в определении. Каждое местоположние идентификатора, замеченного в списке параметров определния, заменяется соответствующей строкой из вызова. Фактичекими параметрами вызова являются строки символов, разделенные запятыми; однако запятые в строке, заключенной в кавычки, или в круглых скобках не являются разделителями параметров. Число формальных и фактических параметров должно совпадать. Строки и символьные константы в символьной строке сканируются в писках формальных параметров, но строки и символьные константы в остальной программе не сканируются в поисках определенных
(с помощью define) идентификаторов.
В обоих случаях строка замещения еще раз сканируется в поисках других определнных идентификаторов. В обоих случаях длинное определение может быть продолжено на другой строке с помощью записи \ в конце продолжаемой строки.
Командная строка вида
#undef идентификатор
влечет отмену препроцессорного определения идентификатра.
11.2 Включение Файлов
Командная строка компилятора вида
#include «имя_файла»
вызывает замену этой строки полным содержимым файла имя_ файла. Сначала именованный файл ищется в директории первончального исходного файла, а затем в стандартных или заданных местах. Альтернативный вариант, командная строка вида
#include «имя_файла»
производит поиск только в стандартном или заданном мете, и не ищет в директории исходного файла. (То, как эти мета задаются, не является частью языка.) Включения с помощью #include могут быть вложенными.
#include «имя_файла»
вызывает замену этой строки полным содержимым файла имя_ файла. Сначала именованный файл ищется в директории первончального исходного файла, а затем в стандартных или заданных местах. Альтернативный вариант, командная строка вида
#include «имя_файла»
производит поиск только в стандартном или заданном мете, и не ищет в директории исходного файла. (То, как эти мета задаются, не является частью языка.) Включения с помощью #include могут быть вложенными.
11.3 Условная Компиляция
Командная строка компилятора вида
#if выражение
проверяет, является ли результатом вычисления выражения не-ноль. Выражение должно быть константным выражением, котрые обсуждаются в #12. Кроме обычных операций С++ может ипользоваться унарная операция defined. При применении к идетификатору она дает значение не-ноль, если этот идентификатор был ранее определен с помощью #define и после этого не было отмены определения с помощью #undef; иначе ее значение 0. Командная строка вида
#ifdef идентификатор
проверяет, определен ли идентификатор в препроцессоре в данный момент; то есть, был ли он объектом командной строки # define. Командная строка вида
#ifndef идентификатор
проверяет, является ли идентификатор неопределенным в препроцессоре в данный момент.
После каждого из трех видов может стоять произвольное количество строк, возможно, содержащих командную строку
#else
и далее до командной строки
#endif
Если проверенное условие истинно, то все строки между #else и #endif игнорируются. Если проверенное условие ложно, то все строки между проверкой и #else или, в случае отсуттвия #else, #endif, игнорируются.
Эти конструкции могут быть вложенными.
#if выражение
проверяет, является ли результатом вычисления выражения не-ноль. Выражение должно быть константным выражением, котрые обсуждаются в #12. Кроме обычных операций С++ может ипользоваться унарная операция defined. При применении к идетификатору она дает значение не-ноль, если этот идентификатор был ранее определен с помощью #define и после этого не было отмены определения с помощью #undef; иначе ее значение 0. Командная строка вида
#ifdef идентификатор
проверяет, определен ли идентификатор в препроцессоре в данный момент; то есть, был ли он объектом командной строки # define. Командная строка вида
#ifndef идентификатор
проверяет, является ли идентификатор неопределенным в препроцессоре в данный момент.
После каждого из трех видов может стоять произвольное количество строк, возможно, содержащих командную строку
#else
и далее до командной строки
#endif
Если проверенное условие истинно, то все строки между #else и #endif игнорируются. Если проверенное условие ложно, то все строки между проверкой и #else или, в случае отсуттвия #else, #endif, игнорируются.
Эти конструкции могут быть вложенными.
11.4 Управление Строкой
Для помощи другим препроцессорам, генерирующим программы на С++, строка вида
#line константа «имя_файла»
заставляет компилятор считать, например, в целях дианостики ошибок, что константа задает номер следущей строки исходного файла, и текущий входной файл именуется идентификтором. Если идентификатор отсутствует, то запомненное имя файла не изменяется.
#line константа «имя_файла»
заставляет компилятор считать, например, в целях дианостики ошибок, что константа задает номер следущей строки исходного файла, и текущий входной файл именуется идентификтором. Если идентификатор отсутствует, то запомненное имя файла не изменяется.
12. Константные Выражения
В нескольких местах С++ требует выражения, вычисление которых дает константу: в качестве границ массива (#8.4), в case выражениях (#9.7), в качестве значений параметров фунции по умолчанию (#8.3), и в инициализаторах (#8.6). В первом случае выражение может включать только целые константы, сивольные константы, константы перечислений, значения несостаных const, инициализированных константными выражениями, и sizeof выражения, возможно, связанные бинарными операциями
+ – * / % amp; ! ^ «„ “» == != « » «= »= amp; amp; !!
или унарными операциями
+ – ~ !
или тернарной операцией
?:
Скобки могут использоваться для группирования, но не для вызова функций.
Во всех остальных случаях константное выражение может также содержать унарную операцию amp;, примененную к внешним или статическим объектам, или к внешним или статическим массивам, индексированным константным выражением. Унарная операция amp; может также быть применена неявно с помощью употребления ниндексированных массивов и функций. Основное правило состоит в том, что инициализаторы должны при вычислении давать контанту или адрес ранее описанного внешнего или статического обйекта плюс или минус константа.
Меньшая широта допустима для константных выражений после #if: недопустимы имена, описанные const, sizeof выражения и перечислимые константы.
13. Соображения Мобильности
Определенные части С++ являются машинно зависимыми по своей сути. Следующий ниже список мест возможных затруднений не претендует на полноту, но может указать на основные из них.
Как показала практика, характеристики аппаратуры в читом виде, такие, как размер слова, свойства плавающей арифмтики и целого деления, не создают особых проблем. Другие апаратные аспекты отражаются на различных программных разработках. Некоторые из них, особенно знаковое расширение (преобразование отрицательного символа в отрицательное целое) и порядок расположения байтов в слове, являются досадными пмехами, за которыми надо тщательно следить. Большинство отальных являются всего лишь мелкими сложностями.
Число регистровых переменных, которые фактически могут быть помещены в регистры, различается от машины к машине, как и множество дейсвующих типов. Тем не менее, все компиляторы на «своей» машине все делают правильно; избыточные или ндействующие описания register игнорируются.
В языке неопределен порядок вычисления параметров фунции. На некоторых машинах он слева направо, а на остальных справа налево. Порядок появления побочных эффектов также ндетерминирован.
Поскольку символьные константы в действительности явлются объектами типа int, то могут быть допустимы многосивольные константы. Однако конкретная реализация очень сильно зависит от машины, поскольку порядок, в котором символы приваиваются слову, различается от машины к машине.
14. Краткое Изложение Синтаксиса
Эта краткая сводка синтаксиса С++ предназначается, чтобы способствовать пониманию. Она не является точной формулирокой языка.
+ – * / % amp; ! ^ «„ “» == != « » «= »= amp; amp; !!
или унарными операциями
+ – ~ !
или тернарной операцией
?:
Скобки могут использоваться для группирования, но не для вызова функций.
Во всех остальных случаях константное выражение может также содержать унарную операцию amp;, примененную к внешним или статическим объектам, или к внешним или статическим массивам, индексированным константным выражением. Унарная операция amp; может также быть применена неявно с помощью употребления ниндексированных массивов и функций. Основное правило состоит в том, что инициализаторы должны при вычислении давать контанту или адрес ранее описанного внешнего или статического обйекта плюс или минус константа.
Меньшая широта допустима для константных выражений после #if: недопустимы имена, описанные const, sizeof выражения и перечислимые константы.
13. Соображения Мобильности
Определенные части С++ являются машинно зависимыми по своей сути. Следующий ниже список мест возможных затруднений не претендует на полноту, но может указать на основные из них.
Как показала практика, характеристики аппаратуры в читом виде, такие, как размер слова, свойства плавающей арифмтики и целого деления, не создают особых проблем. Другие апаратные аспекты отражаются на различных программных разработках. Некоторые из них, особенно знаковое расширение (преобразование отрицательного символа в отрицательное целое) и порядок расположения байтов в слове, являются досадными пмехами, за которыми надо тщательно следить. Большинство отальных являются всего лишь мелкими сложностями.
Число регистровых переменных, которые фактически могут быть помещены в регистры, различается от машины к машине, как и множество дейсвующих типов. Тем не менее, все компиляторы на «своей» машине все делают правильно; избыточные или ндействующие описания register игнорируются.
В языке неопределен порядок вычисления параметров фунции. На некоторых машинах он слева направо, а на остальных справа налево. Порядок появления побочных эффектов также ндетерминирован.
Поскольку символьные константы в действительности явлются объектами типа int, то могут быть допустимы многосивольные константы. Однако конкретная реализация очень сильно зависит от машины, поскольку порядок, в котором символы приваиваются слову, различается от машины к машине.
14. Краткое Изложение Синтаксиса
Эта краткая сводка синтаксиса С++ предназначается, чтобы способствовать пониманию. Она не является точной формулирокой языка.
14.1 Выражения
выражение: терм выражение бинарная_операция выражение выражение ? выражение : выражение список_выражений
список_выражений: выражение список_выражений , выражение
терм: первичное_выражение унарная_операция терм терм ++ терм – sizeof выражение sizeof ( имя_типа ) ( имя_типа) выражение простое_имя_типа ( список_выражений ) new имя_типа инициализатор opt new ( имя_типа ) delete выражение delete [ выражение ] выражение
первичное_выражение: id :: идентификатор константа строка this ( выражение ) первичное_выражение[ выражение ] первичное_выражение ( список_выражений opt ) первичное_выражение.id первичное_выражение-»id
id: идентификатор typedef-имя :: идентификатор typedef-имя :: имя_функции_операции
операция: унарная_операция бинарная_операция специальная_операция операция_свободной_памяти
Бинарные операции имеют приоритет, убывающий в указанном порядке:
бинарная_операция: одна из * / % + – «„ “» « »
== != amp; ^ ! amp; amp; !! операция_присваивания
операция_присваивания: одна из = += -= *= /= %= ^= amp;= != »»= ««=
унарная_операция: одна из * amp; + – ~ ! ++ –
специальная_операция: одна из () []
операция_свободной_памяти: одна из new delete
имя_типа: спецификаторы_описания абстрактный_описатель
абстрактный_описатель: пустой * абстрактный_описатель абстрактный_описатель ( список_описаний_параметров ) абстрактный_описатель [ константное_выражение opt ]
простое_имя_типа: typedef-имя char short int long unsigned float double void
typedef-имя: идентификатор
список_выражений: выражение список_выражений , выражение
терм: первичное_выражение унарная_операция терм терм ++ терм – sizeof выражение sizeof ( имя_типа ) ( имя_типа) выражение простое_имя_типа ( список_выражений ) new имя_типа инициализатор opt new ( имя_типа ) delete выражение delete [ выражение ] выражение
первичное_выражение: id :: идентификатор константа строка this ( выражение ) первичное_выражение[ выражение ] первичное_выражение ( список_выражений opt ) первичное_выражение.id первичное_выражение-»id
id: идентификатор typedef-имя :: идентификатор typedef-имя :: имя_функции_операции
операция: унарная_операция бинарная_операция специальная_операция операция_свободной_памяти
Бинарные операции имеют приоритет, убывающий в указанном порядке:
бинарная_операция: одна из * / % + – «„ “» « »
== != amp; ^ ! amp; amp; !! операция_присваивания
операция_присваивания: одна из = += -= *= /= %= ^= amp;= != »»= ««=
унарная_операция: одна из * amp; + – ~ ! ++ –
специальная_операция: одна из () []
операция_свободной_памяти: одна из new delete
имя_типа: спецификаторы_описания абстрактный_описатель
абстрактный_описатель: пустой * абстрактный_описатель абстрактный_описатель ( список_описаний_параметров ) абстрактный_описатель [ константное_выражение opt ]
простое_имя_типа: typedef-имя char short int long unsigned float double void
typedef-имя: идентификатор
14.2 Описания
описание: спецификаторы_описания opt список_описателей opt ; описание_имени asm-описание
описание_имени: сост идентификатор ; enum идентификатор ;
сост:
class struct union
asm-описание: asm ( строка ) ;
спецификаторы_описания: спецификатор_описания спецификаторы_описания opt
спецификатор_описания: спецификатор_класса_памяти спецификатор_типа спецификатор_функции typedef friend
спецификатор_типа: простое_имя_типа спецификатор_класса спецификатор_enum усложненный_спецификатор_типа const
спецификатор_класса_памяти: auto extern register static
спецификатор_функции: inline overload virtual
усложненный_спецификатор_типа: ключ typedef-имя ключ идентификатор
ключ: class struct union enum
список_описателей: иниц-описатель иниц-описатель , список_описателей
иниц-описатель: описатель инициализатор opt
описатель: оп_имя ( описатель ) * const opt описатель amp; const opt описатель
описатель ( список_описаний_параметров ) описатель [ константное_выражение opt ]
оп_имя: простое_оп_имя typedef-имя :: простое_оп_имя
простое_оп_имя: идентификатор typedef-имя ~ typedef-имя имя_функции_операции имя_функции_преобразования
имя_функции_операции: operator операция
имя_функции_преобразования operator тип
список_описаний_параметров: список_описаний_прм opt ... opt
список_описаний_прм: список_описаний_прм , описание_параметра описание_параметра
описание_параметра: спецификаторы_описания описатель = выражение спецификаторы_описания описатель = константное_выражение спецификаторы_описания абстракт_описатель = выражение спецификаторы_описания абстракт_описатель = выражение
спецификатор_класса: заголовок_класса (* список_членов opt *) заголовок_класса (* список_членов opt public : список_членов opt *)
заголовок_класса: сост идентификатор opt сост идентификатор opt : public opt typedef-имя
список_членов: описание_члена список_членов opt
описание_члена: спецификаторы_описания opt описатель_члена инициализатор opt ; определение_функции opt
описатель_члена: описатель идентификатор opt : константное_выражение
инициализатор: = выражение = (* список_инициализаторов *) = (* список_инициализаторов , *) ( список_выражений )
список_инициализаторов: выражение список_инициализаторов , список_инициализаторов (* список_инициализаторов *)
спецификатор_enum: enum идентификатор opt (* enum-список *)
enum-список: перечислитель enum-список , перечислитель
перечислитель: идентификатор идентификатор = константное_выражение
описание_имени: сост идентификатор ; enum идентификатор ;
сост:
class struct union
asm-описание: asm ( строка ) ;
спецификаторы_описания: спецификатор_описания спецификаторы_описания opt
спецификатор_описания: спецификатор_класса_памяти спецификатор_типа спецификатор_функции typedef friend
спецификатор_типа: простое_имя_типа спецификатор_класса спецификатор_enum усложненный_спецификатор_типа const
спецификатор_класса_памяти: auto extern register static
спецификатор_функции: inline overload virtual
усложненный_спецификатор_типа: ключ typedef-имя ключ идентификатор
ключ: class struct union enum
список_описателей: иниц-описатель иниц-описатель , список_описателей
иниц-описатель: описатель инициализатор opt
описатель: оп_имя ( описатель ) * const opt описатель amp; const opt описатель
описатель ( список_описаний_параметров ) описатель [ константное_выражение opt ]
оп_имя: простое_оп_имя typedef-имя :: простое_оп_имя
простое_оп_имя: идентификатор typedef-имя ~ typedef-имя имя_функции_операции имя_функции_преобразования
имя_функции_операции: operator операция
имя_функции_преобразования operator тип
список_описаний_параметров: список_описаний_прм opt ... opt
список_описаний_прм: список_описаний_прм , описание_параметра описание_параметра
описание_параметра: спецификаторы_описания описатель = выражение спецификаторы_описания описатель = константное_выражение спецификаторы_описания абстракт_описатель = выражение спецификаторы_описания абстракт_описатель = выражение
спецификатор_класса: заголовок_класса (* список_членов opt *) заголовок_класса (* список_членов opt public : список_членов opt *)
заголовок_класса: сост идентификатор opt сост идентификатор opt : public opt typedef-имя
список_членов: описание_члена список_членов opt
описание_члена: спецификаторы_описания opt описатель_члена инициализатор opt ; определение_функции opt
описатель_члена: описатель идентификатор opt : константное_выражение
инициализатор: = выражение = (* список_инициализаторов *) = (* список_инициализаторов , *) ( список_выражений )
список_инициализаторов: выражение список_инициализаторов , список_инициализаторов (* список_инициализаторов *)
спецификатор_enum: enum идентификатор opt (* enum-список *)
enum-список: перечислитель enum-список , перечислитель
перечислитель: идентификатор идентификатор = константное_выражение
14.3 Операторы
составной_оператор: (* список_операторов opt *)
список_операторов: оператор оператор список_операторов
оператор: описание составной_оператор выражение opt ; if ( выражение ) оператор if ( выражение ) оператор else оператор while ( выражение ) оператор do оператор while ( выражение ) ; for ( оператор выражение opt ; выражение opt ) оператор switch ( выражение ) оператор case константное_выражение : оператор default : оператор break ; continue ; return выражение opt ; goto идентификатор ; идентификатор : оператор
список_операторов: оператор оператор список_операторов
оператор: описание составной_оператор выражение opt ; if ( выражение ) оператор if ( выражение ) оператор else оператор while ( выражение ) оператор do оператор while ( выражение ) ; for ( оператор выражение opt ; выражение opt ) оператор switch ( выражение ) оператор case константное_выражение : оператор default : оператор break ; continue ; return выражение opt ; goto идентификатор ; идентификатор : оператор
14.4 Внешние определения
программа: внешнее_определение внешнее_определение программа
внешнее_определение: определение_функции описание
определение_функции: спецификаторы_описания opt описатель_функции инициализатор_базового opt тело_функции
описатель_функции: описатель ( список_описаний_параметров )
тело_функции: составной_оператор
инициализатор_базового: : ( список_инициализаторов_членов opt )
внешнее_определение: определение_функции описание
определение_функции: спецификаторы_описания opt описатель_функции инициализатор_базового opt тело_функции
описатель_функции: описатель ( список_описаний_параметров )
тело_функции: составной_оператор
инициализатор_базового: : ( список_инициализаторов_членов opt )
14.5 Препроцессор
#define идентификатор строка_лексем
#define идентификатор( идентификатор,...,идентификатор ) строка лексем #else #endif #if выражение #ifdef идентификатор #ifndef идентификатор #include «имя_файла» #include «имя_файла» #line константа «имя_файла» #undef идентификатор
#define идентификатор( идентификатор,...,идентификатор ) строка лексем #else #endif #if выражение #ifdef идентификатор #ifndef идентификатор #include «имя_файла» #include «имя_файла» #line константа «имя_файла» #undef идентификатор
15. Отличия от C
15.1 Расширения
Типы параметров функции могут быть заданы (#8.4) и будут проверяться (#7.1). Могут выполняться преобразования типов (# 7.1).
Для выражений с числами с плавающей точкой может исползоваться плавающая арифметика одинарной точности; #6.2.
Имена функций могут быть перегружены; #8.9.
Операции могут быть перегружены; 7.16, #8.5.11.
Функции могут быть inline-подставляемыми; #8.1.
Объекты данных могут быть константными (const); #8.3.
Могут быть описаны объекты ссылочного типа; #8.4, #8.6.3
Операции new и delete обеспечивают свободное хранение в памяти, #7.2.
Классы могут обеспечивать сокрытие данных (#8.5.9), грантированную инициализацию (#8.6.2), определяемые пользовтелем преобразвания (#8.5.6), и динамическое типизирование через использование виртуальных функций (#8.5.4).
Имя класса или перечисления является именем типа; #8.5.
Любой указатель может присваиваться void* без применеия приведения к типу; #7.14.
Описание внутри блока является оператором; #9.14.
Можно описывать безымянные объединения; #8.5.13.
Для выражений с числами с плавающей точкой может исползоваться плавающая арифметика одинарной точности; #6.2.
Имена функций могут быть перегружены; #8.9.
Операции могут быть перегружены; 7.16, #8.5.11.
Функции могут быть inline-подставляемыми; #8.1.
Объекты данных могут быть константными (const); #8.3.
Могут быть описаны объекты ссылочного типа; #8.4, #8.6.3
Операции new и delete обеспечивают свободное хранение в памяти, #7.2.
Классы могут обеспечивать сокрытие данных (#8.5.9), грантированную инициализацию (#8.6.2), определяемые пользовтелем преобразвания (#8.5.6), и динамическое типизирование через использование виртуальных функций (#8.5.4).
Имя класса или перечисления является именем типа; #8.5.
Любой указатель может присваиваться void* без применеия приведения к типу; #7.14.
Описание внутри блока является оператором; #9.14.
Можно описывать безымянные объединения; #8.5.13.
15.2 Сводка Несовместимостей
Большинство конструкций C допустимы в С++ без изменения их смысла. Исключения из этого следующие:
Программы, использующие одно из новых ключевых слов
class const delete friend inline new operator overload public signed this virtual volatile
как идентификаторы, недопустимы.
Описание функции f(); означает, что f не получает парметров, в C же это значит, что f может получать параметр свершенно любого типа.
В C внешнее имя может определяться несколько раз, а в С+ + оно должно быть определено ровно один раз.
Имена классов в С++ находятся в том же пространстве, что и прочие имена, поэтому конструкции вроде
int s; struct s (* /* ... */ *); f() (* s = 1; *)
использоваться не могут. Однако, для разрешения болшинства конфликтов может применяться явное использование class, struct, union, enum (#8.2) или :: (#7.1). Например:
int s; struct s (* /* ... */ *); void f() (*int s; struct s a; *) void g() (* ::s = 1; *)
Программы, использующие одно из новых ключевых слов
class const delete friend inline new operator overload public signed this virtual volatile
как идентификаторы, недопустимы.
Описание функции f(); означает, что f не получает парметров, в C же это значит, что f может получать параметр свершенно любого типа.
В C внешнее имя может определяться несколько раз, а в С+ + оно должно быть определено ровно один раз.
Имена классов в С++ находятся в том же пространстве, что и прочие имена, поэтому конструкции вроде
int s; struct s (* /* ... */ *); f() (* s = 1; *)
использоваться не могут. Однако, для разрешения болшинства конфликтов может применяться явное использование class, struct, union, enum (#8.2) или :: (#7.1). Например:
int s; struct s (* /* ... */ *); void f() (*int s; struct s a; *) void g() (* ::s = 1; *)
15.3 Анахронизмы
Изложенные здесь расширения могут предоставляться для того, чтобы упростить использование C программ как С++ прорамм. Обратите внимание, что каждая из этих возможностей сдержит нежелательные аспекты. Предоставляющая их реализация должна также обеспечивать пользователю способ удостовериться, что они не встречаются в исходном файле.
Прежнее неопределенное имя может использоваться как имя функции в вызове. В этом случае имя будет неявно описано как
функция, возвращающая int с типом параметра (...).
Ключевое слово void может использоваться для указания того, что функция не получает параметров, так что (void) эвивалентно ().
Могут использоваться программы, в которых используется синтаксис определения функций в C
старое_определение_функции: спецификаторы_описания opt старый_описатель_функции список_описателей тело_функции
старый_описатель_функции: описатель (* список_параметров *)
список_параметров: идентификатор идентификатор , идентификатор
например,
max(a,b) (* return (a«b) ? b : a; *)
Если функция, описанная как эта, была ранее описана, тип ее параметра будет принят (...), то есть, непроверенный. Если она была описана, ее тип должен согласоваться с типом описния.
Вместо :: может использоваться точка для спецификации имени в определении функции члена. Например:
int cl.fct() (* /* ... */ *)
Одно и то же имя может быть описано одновременно и для класса или перечисления, и для объекта данных или функции в одной и той же области видимости.
Прежнее неопределенное имя может использоваться как имя функции в вызове. В этом случае имя будет неявно описано как
функция, возвращающая int с типом параметра (...).
Ключевое слово void может использоваться для указания того, что функция не получает параметров, так что (void) эвивалентно ().
Могут использоваться программы, в которых используется синтаксис определения функций в C
старое_определение_функции: спецификаторы_описания opt старый_описатель_функции список_описателей тело_функции
старый_описатель_функции: описатель (* список_параметров *)
список_параметров: идентификатор идентификатор , идентификатор
например,
max(a,b) (* return (a«b) ? b : a; *)
Если функция, описанная как эта, была ранее описана, тип ее параметра будет принят (...), то есть, непроверенный. Если она была описана, ее тип должен согласоваться с типом описния.
Вместо :: может использоваться точка для спецификации имени в определении функции члена. Например:
int cl.fct() (* /* ... */ *)
Одно и то же имя может быть описано одновременно и для класса или перечисления, и для объекта данных или функции в одной и той же области видимости.