Операторы в C и C ++ - Operators in C and C++

Это список операторы в C и C ++ языки программирования. Все перечисленные операторы существуют в C ++; четвертый столбец «Включено в C» указывает, присутствует ли оператор также в C. Обратите внимание, что C не поддерживает перегрузка оператора.

Когда не перегружен, для операторов &&, ||, и ,оператор запятой ), Существует точка последовательности после оценки первого операнда.

C ++ также содержит преобразование типов операторы const_cast, static_cast, dynamic_cast, и reinterpret_cast. Форматирование этих операторов означает, что их уровень приоритета не важен.

Большинство операторов, доступных в C и C ++, также доступны в других C-семья языки, такие как C #, D, Ява, Perl, и PHP с тем же приоритетом, ассоциативностью и семантикой.

Стол

Для целей этих таблиц а, б, и c представляют допустимые значения (литералы, значения из переменных или возвращаемое значение), имена объектов или lvalue, в зависимости от ситуации. р, S и Т подставка для любого типа (ов), и K для типа класса или перечислимого типа.

Арифметические операторы

Имя оператораСинтаксисМожет перегрузить в C ++Включено
в C
Примеры прототипов C ++
Как член KОпределения вне класса
Базовое заданиеа = бдадар& K::оператор =(S б);Нет данных
Добавлениеа + бдадар K::оператор +(S б);р оператор +(K а, S б);
Вычитаниеа - бдадар K::оператор -(S б);р оператор -(K а, S б);
Унарный плюс (целочисленное продвижение )+ададар K::оператор +();р оператор +(K а);
Унарный минус (Противоположное число )-ададар K::оператор -();р оператор -(K а);
Умножениеа * бдадар K::оператор *(S б);р оператор *(K а, S б);
Разделениеа / бдадар K::оператор /(S б);р оператор /(K а, S б);
По модулю (целочисленный остаток)[а]а % бдадар K::оператор %(S б);р оператор %(K а, S б);
ПриращениеПрефикс++ададар& K::оператор ++();р& оператор ++(K& а);
Постфикса++дадар K::оператор ++(int);р оператор ++(K& а, int);
Примечание: C ++ использует безымянный фиктивный параметр int чтобы различать префиксные и постфиксные операторы приращения.
ДекрементПрефикс--ададар& K::оператор --();р& оператор --(K& а);
Постфикса--дадар K::оператор --(int);р оператор --(K& а, int);
Примечание: C ++ использует безымянный фиктивный параметр int чтобы различать префиксные и постфиксные операторы декремента.

Операторы сравнения / операторы отношения

Имя оператораСинтаксисМожет перегрузить в C ++Включено
в C
Примеры прототипов
Как член KОпределения вне класса
Равноа == бдадаbool K::оператор ==(S const& б) const;bool оператор ==(K const& а, S const& б);
Не равноа != б
а not_eq б[b]
дадаbool K::оператор !=(S const& б); bool K::оператор !=(S const& б) const;bool оператор !=(K const& а, S const& б);
Лучше чема > бдадаbool K::оператор >(S const& б) const;bool оператор >(K const& а, S const& б);
Меньше, чема < бдадаbool K::оператор <(S const& б) const;bool оператор <(K const& а, S const& б);
Больше или равноа >= бдадаbool K::оператор >=(S const& б) const;bool оператор >=(K const& а, S const& б);
Меньше или равноа <= бдадаbool K::оператор <=(S const& б) const;bool оператор <=(K const& а, S const& б);
Трехстороннее сравнение[c]а <=> бдаНетстандартное::weak_equality K::оператор <=>(const S &б);стандартное::weak_equality оператор <=>(const K &а, const S &б);
Примечание. Всего у оператора 6 типов возврата: std :: weak_equality, std :: strong_equality, std :: partial_ordering, std :: weak_ordering, std :: strong_ordering, и std :: common_comparison_category

Логические операторы

Имя оператораСинтаксисМожет перегрузить в C ++Включено
в C
Примеры прототипов C ++
Как член KОпределения вне класса
Логическое отрицание (НЕ)!а
нет а[b]
дадаbool K::оператор !();bool оператор !(K а);
Логическое Иа && б
а и б[b]
дадаbool K::оператор &&(S б);bool оператор &&(K а, S б);
Логическое ИЛИа || б
а или же б[b]
дадаbool K::оператор ||(S б);bool оператор ||(K а, S б);

Побитовые операторы

Имя оператораСинтаксисМожет перегрузить в C ++Включено
в C
Примеры прототипов
Как член KОпределения вне класса
Побитовое НЕ~а
компл а[b]
дадар K::оператор ~();р оператор ~(K а);
Побитовое Иа & б
а битанд б[b]
дадар K::оператор &(S б);р оператор &(K а, S б);
Побитовое ИЛИа | б
а кусачий б[b]
дадар K::оператор |(S б);р оператор |(K а, S б);
Побитовое исключающее ИЛИа ^ б
а xor б[b]
дадар K::оператор ^(S б);р оператор ^(K а, S б);
Побитовый сдвиг влево[d]а << бдадар K::оператор <<(S б);р оператор <<(K а, S б);
Побитовый сдвиг вправо[d][e]а >> бдадар K::оператор >>(S б);р оператор >>(K а, S б);

Операторы составного присваивания

Имя оператораСинтаксисСмыслМожет перегрузить в C ++Включено
в C
Примеры прототипов C ++
Как член KОпределения вне класса
Дополнительное заданиеа += ба = а + бдадар& K::оператор +=(S б);р& оператор +=(K& а, S б);
Присваивание вычитанияа -= ба = а - бдадар& K::оператор -=(S б);р& оператор -=(K& а, S б);
Присваивание умноженияа *= ба = а * бдадар& K::оператор *=(S б);р& оператор *=(K& а, S б);
Назначение дивизионаа /= ба = а / бдадар& K::оператор /=(S б);р& оператор /=(K& а, S б);
Назначение по модулюа %= ба = а % бдадар& K::оператор %=(S б);р& оператор %=(K& а, S б);
Побитовое И присваиваниеа &= б
а and_eq б[b]
а = а & бдадар& K::оператор &=(S б);р& оператор &=(K& а, S б);
Назначение побитового ИЛИа |= б
а or_eq б[b]
а = а | бдадар& K::оператор |=(S б);р& оператор |=(K& а, S б);
Назначение побитового XORа ^= б
а xor_eq б[b]
а = а ^ бдадар& K::оператор ^=(S б);р& оператор ^=(K& а, S б);
Назначение побитового сдвига влевоа <<= ба = а << бдадар& K::оператор <<=(S б);р& оператор <<=(K& а, S б);
Назначение побитового сдвига вправо[e]а >>= ба = а >> бдадар& K::оператор >>=(S б);р& оператор >>=(K& а, S б);

Операторы-члены и указатели

Имя оператораСинтаксисМожет перегрузить в C ++Включено
в C
Примеры прототипов C ++
Как член KОпределения вне класса
Нижний индекса[б]дадар& K::оператор [](S б);
Нет данных
Косвенность ("объект, на который указывает а")*ададар& K::оператор *();р& оператор *(K а);
Address-of ("адрес а")&ададар* K::оператор &();р* оператор &(K а);
Разыменование структуры ("член б объекта, на который указывает а")а->бдадар* K::оператор ->();[f]
Нет данных
Ссылка на структуру ("член б объекта а")а.бНетдаНет данных
Участник выбран указатель на член б объекта, на который указывает а[грамм]а->*бдаНетр& K::оператор ->*(S б);р& оператор ->*(K а, S б);
Участник объекта а выбран указатель на член ба.*бНетНетНет данных

Другие операторы

Имя оператораСинтаксисМожет перегрузить в C ++Включено
в C
Примеры прототипов
Как член KОпределения вне класса
Функция вызов
Видеть Функциональный объект.
а(а1, а2)дадар K::оператор ()(S а, Т б, ...);Нет данных
Запятаяа, бдадар K::оператор ,(S б);р оператор ,(K а, S б);
Тернарный условныйа ? б : cНетдаНет данных
Разрешение прицелаа::бНетНетНет данных
Пользовательские литералы[час]
начиная с C ++ 11
"а" _bдаНетНет данныхр оператор "" _b(Т а)
Размерразмер(а)[я]
размер(тип)
НетдаНет данных
Размер пакет параметров
начиная с C ++ 11
размер...(Аргументы)НетНетНет данных
Alignof
начиная с C ++ 11
выровнять(тип)
или же _Alignof(тип)[j]
НетдаНет данных
Идентификация типатипичный(а)
типичный(тип)
НетНетНет данных
Преобразование (С-стиль бросок)(тип) ададаK::оператор р();[2]Нет данных
Преобразованиетип(а)НетНетПримечание: ведет себя как const_cast / static_cast / reinterpret_cast[3]
static_cast преобразованиеstatic_cast<тип> (а)даНетK::оператор р();
явный K::оператор р(); начиная с C ++ 11
Нет данных
Примечание: для пользовательских преобразований тип возвращаемого значения неявно и обязательно соответствует имени оператора.
динамический состав преобразованиеdynamic_cast<тип> (а)НетНетНет данных
const_cast преобразованиеconst_cast<тип> (а)НетНетНет данных
reinterpret_cast преобразованиеreinterpret_cast<тип> (а)НетНетНет данных
Выделить хранилищеновый типдаНетпустота* K::оператор новый(size_t Икс);пустота* оператор новый(size_t Икс);
Выделить хранилище (массив)новый тип[п]даНетпустота* K::оператор новый[](size_t а);пустота* оператор новый[](size_t а);
Освободить место для храненияУдалить адаНетпустота K::оператор Удалить(пустота* а);пустота оператор Удалить(пустота* а);
Освободить хранилище (массив)Удалить[] адаНетпустота K::оператор Удалить[](пустота* а);пустота оператор Удалить[](пустота* а);
Проверка исключения
начиная с C ++ 11
нет кроме(а)НетНетНет данных

Примечания:

  1. ^ Оператор модуля работает только с целочисленными операндами, для чисел с плавающей запятой вместо этого должна использоваться библиотечная функция (например, fmod ).
  2. ^ а б c d е ж грамм час я j k Требует iso646.h в C. См. Синонимы операторов C ++
  3. ^ О C ++ 20 трехстороннее сравнение
  4. ^ а б В контексте iostreams писатели часто будут ссылаться на << и >> как операторы «ввод» или «вставка потока» и «получение» или «извлечение потока» соответственно.
  5. ^ а б Согласно стандарту C99 сдвиг отрицательного числа вправо определяется реализацией. Большинство реализаций, например GCC,[1] использовать арифметический сдвиг (т.е. расширение знака), но логический сдвиг возможно.
  6. ^ Тип возврата оператор->() должен быть типом, для которого -> может применяться операция, например, указатель типа. Если Икс относится к типу C куда C перегрузки оператор->(), Икс->у расширяется до Икс.оператор->()->у.
  7. ^ Мейерс, Скотт (октябрь 1999 г.), «Оператор внедрения -> * для смарт-указателей» (PDF), Журнал доктора Добба, Аристея.
  8. ^ О C ++ 11 Пользовательские литералы
  9. ^ Скобки не нужны при выборе размера значения, только при выборе размера типа. Однако они обычно используются независимо.
  10. ^ C ++ определяет выровнять оператор, тогда как C определяет _Alignof. Оба оператора имеют одинаковую семантику.

Приоритет оператора

В следующей таблице перечислены приоритет и ассоциативность всех операторов в C и C ++ языков (когда операторы также существуют в Ява, Perl, PHP и многие другие недавние языки, приоритет такой же, как и данный[нужна цитата ]). Операторы перечислены сверху вниз в порядке убывания приоритета. Приоритет по убыванию относится к приоритету группировки операторов и операндов. Рассматривая выражение, оператор, который указан в некоторой строке, будет сгруппирован до любого оператора, который указан в строке ниже. Операторы, находящиеся в одной ячейке (в ячейке может быть несколько строк операторов), группируются с одинаковым приоритетом в заданном направлении. Перегрузка не влияет на приоритет оператора.

Синтаксис выражений в C и C ++ определяется грамматика фразовой структуры.[4] Приведенная здесь таблица была выведена из грамматики.[нужна цитата ] Для стандарта ISO C 1999 в примечании 71 к разделу 6.5.6 указано, что грамматика C, предусмотренная спецификацией, определяет приоритет операторов C, а также говорится, что приоритет операторов, вытекающий из грамматики, точно соответствует порядку разделов в спецификации:

"Синтаксис [C] [т.е. грамматика] определяет приоритет операторов при оценке выражения, который совпадает с порядком основных подпунктов этого подпункта, сначала наивысший приоритет ".[5]

Таблица приоритета, хотя в большинстве случаев адекватна, не может разрешить некоторые детали. В частности, отметим, что тернарный оператор позволяет любое произвольное выражение в качестве своего среднего операнда, несмотря на то, что оно указано как имеющее более высокий приоритет, чем операторы присваивания и запятой. Таким образом а? б, в: г интерпретируется как а? (б, в): г, а не как бессмысленное (а? б), (в: г). Итак, выражение в середине условного оператора (между ? и :) анализируется как заключенный в скобки. Также обратите внимание, что непосредственный, без скобок результат выражения приведения C не может быть операндом размер. Следовательно, sizeof (число) * x интерпретируется как (размер (число)) * х и нет sizeof ((число) * х).

ПриоритетОператорОписаниеАссоциативность
1

наибольший

::Разрешение прицела (Только C ++)Никто
2++Постфиксное приращениеСлева направо
--Постфиксный декремент
()Вызов функции
[]Индексы массива
.Выбор элемента по ссылке
->Выбор элемента с помощью указателя
typeid ()Информация о типе времени выполнения (Только C ++) (см. типичный )
const_castПриведение типов (только C ++) (см. const_cast )
dynamic_castПриведение типов (только C ++) (см. динамический состав )
reinterpret_castПриведение типов (только C ++) (см. reinterpret_cast )
static_castПриведение типов (только C ++) (см. static_cast )
3++Приращение префиксаСправа налево
--Префиксный декремент
+Унарный плюс
-Унарный минус
!Логическое НЕ
~Побитовое НЕ (одно дополнение)
(тип)Приведение типов
*Косвенное обращение (разыменование)
&Адрес
размерРазмер
_AlignofТребование выравнивания (начиная с C11)
новый, новый[]Распределение динамической памяти (только C ++)
Удалить, Удалить[]Динамическое освобождение памяти (только C ++)
4.*Указатель на член (только C ++)Слева направо
->*Указатель на член (только C ++)
5*УмножениеСлева направо
/Разделение
%По модулю (остаток)
6+ДобавлениеСлева направо
-Вычитание
7<<Побитовое левый "шифтСлева направо
>>Побитовое сдвиг вправо
8<=>Трехстороннее сравнение (Представлено в C ++ 20 - только C ++)Слева направо
9<Меньше, чемСлева направо
<=Меньше или равно
>Лучше чем
>=Больше или равно
10==РавноСлева направо
!=Не равно
11&Побитовое ИСлева направо
12^Побитовое исключающее ИЛИ (исключающее ИЛИ)Слева направо
13|Побитовое ИЛИ (включительно или)Слева направо
14&&Логическое ИСлева направо
15||Логическое ИЛИСлева направо
16?:Троичный условный (см. ?: )Справа налево
=Прямое назначение
+=Переуступка по сумме
-=Присвоение по разнице
*=Назначение по продукту
/=Присвоение по частному
%=Присвоение остатка
<<=Присваивание с помощью побитового сдвига влево
>>=Присваивание с помощью побитового сдвига вправо
&=Присваивание поразрядным И
^=Присваивание с помощью побитового XOR
|=Присваивание поразрядным ИЛИ
бросатьОператор выброса (выброс исключений, только C ++)
17

самый низкий

,ЗапятаяСлева направо

[6][7][8]

Примечания

Таблица приоритета определяет порядок привязки в связанных выражениях, если он явно не указан круглыми скобками.

  • Например, ++ x * 3 является неоднозначным без каких-либо правил приоритета. Таблица приоритета говорит нам, что: Икс «привязан» к ++ чем *, так что все ++ делает (сейчас или позже - см. ниже), ТОЛЬКО для Икс (а не х * 3); это эквивалентно (++ x, х * 3).
  • Аналогично с 3 * х ++, где хотя пост-исправление ++ разработан, чтобы действовать ПОСЛЕ того, как все выражение оценивается, таблица приоритетов дает понять, что ТОЛЬКО Икс увеличивается (и НЕ 3 * х). Фактически выражение (tmp = x ++, 3 * тмп) оценивается с помощью tmp являясь временной ценностью. Функционально это эквивалентно чему-то вроде (tmp = 3 * x, ++ x, tmp).
Приоритет и привязки
  • Абстрагируясь от вопроса приоритета или привязки, рассмотрим приведенную выше диаграмму для выражения 3 + 2 * y [i] ++. Задача компилятора - преобразовать диаграмму в выражение, в котором несколько унарных операторов (назовите их 3+ (.), 2 * (.), (.) ++ и (.) [I]) конкурируют за связывание к y. Таблица приоритета определяет последнее подвыражение, с которым они действуют: (.) ​​[I] действует только на y, (.) ++ действует только на y [i], 2 * (.) Действует только на y [ i] ++ и 3+ (.) действуют «только» на 2 * ((y [i]) ++). Важно отметить, что подвыражение ЧТО выполняется каждым оператором, ясно из таблицы приоритета, но КОГДА каждый оператор действует, таблица приоритета не разрешает; в этом примере оператор (.) ++ действует только на y [i] в ​​соответствии с правилами приоритета, но только уровни привязки не указывают время постфикса ++ (оператор (.) ++ действует только после y [i ] оценивается в выражении).

Многим операторам, содержащим многосимвольные последовательности, даются «имена», составленные из имени оператора каждого символа. Например, += и -= часто называют плюс равно (а) и минус равен (а), вместо более подробных «присваивание добавлением» и «присваивание вычитанием». Связывание операторов в C и C ++ определяется (в соответствующих стандартах) грамматикой языка с факторизацией, а не таблицей приоритета. Это создает некоторые тонкие конфликты. Например, в C синтаксис условного выражения:

логичный-ИЛИ ЖЕ-выражение ? выражение : условный-выражение

а в C ++ это:

логичный-ИЛИ ЖЕ-выражение ? выражение : назначение-выражение

Отсюда выражение:

е = а 

анализируется по-разному на двух языках. В C это выражение является синтаксической ошибкой, потому что синтаксис выражения присваивания в C:

унарный-выражение '=' назначение-выражение

В C ++ он разбирается как:

е = (а < d ? а++ : (а = d))

что является допустимым выражением.[9][10]

Если вы хотите использовать оператор-запятую в одном аргументе функции, назначении переменных или другом списке, разделенном запятыми, вам необходимо использовать круглые скобки,[11][12] например.:

int а = 1, б = 2, странная переменная = (++а, б), d = 4;

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

Приоритет поразрядных логических операторов подвергся критике.[13] Концептуально & и | являются арифметическими операторами, такими как * и +.

Выражение а & б == 7 синтаксически разбирается как а & (б == 7) тогда как выражение а + б == 7 разбирается как (а + б) == 7. Это требует, чтобы скобки использовались чаще, чем в противном случае.

Исторически не существовало синтаксического различия между побитовыми и логическими операторами. В BCPL, B и ранний C, операторы && || не существовало. Вместо & | имели разное значение в зависимости от того, используются ли они в «контексте истинного значения» (т.е. когда ожидалось логическое значение, например, в если (а==б & c) {...} он вел себя как логический оператор, но в c = а & б он вёл себя как побитовый). Он был сохранен, чтобы сохранить Обратная совместимость с существующими установками.[14]

Более того, в C ++ (и более поздних версиях C) операции равенства, за исключением оператора трехстороннего сравнения, yield bool значения типа, которые концептуально представляют собой один бит (1 или 0) и как таковые не принадлежат должным образом к «побитовым» операциям.

Синонимы операторов C ++

C ++ определяет[15] определенные ключевые слова, которые действуют как псевдонимы для ряда операторов:

Ключевое словоОператор
и&&
and_eq&=
битанд&
кусачий|
компл~
нет!
not_eq!=
или же||
or_eq|=
xor^
xor_eq^=

Их можно использовать точно так же, как и заменяемые ими знаки препинания, поскольку они не являются одним и тем же оператором под другим именем, а скорее являются простой заменой токенов для имя (символьная строка) соответствующего оператора. Это означает, что выражения (a> 0, а не флаг) и (флаг a> 0 &&!) имеют одинаковые значения. Это также означает, например, что битанд ключевое слово может использоваться не только для замены побитовое и оператор, но и адрес оператор, и его даже можно использовать для указания ссылочных типов (например, int bit и ref = n). Спецификация ISO C допускает использование этих ключевых слов в качестве макросов препроцессора в файле заголовка. iso646.h. Для совместимости с C C ++ предоставляет заголовок ciso646, включение которых не имеет никакого эффекта.

Смотрите также

Рекомендации

  1. ^ "Целочисленная реализация", GCC 4.3.3, GNU.
  2. ^ "определяемое пользователем преобразование". Получено 5 апреля 2020.
  3. ^ Явное преобразование типа в C ++
  4. ^ ISO / IEC 9899: 201x языков программирования - C. open-std.org - Комитет по стандартам C. 19 декабря 2011. с. 465.
  5. ^ стандарт ISO C 1999, раздел 6.5.6 примечание 71 (Технический отчет). ISO. 1999 г.
  6. ^ "Приоритет оператора C - cppreference.com". en.cppreference.com. Получено 16 июля 2019.
  7. ^ «Встроенные операторы C ++, приоритет и ассоциативность». docs.microsoft.com. Получено 11 мая 2020.
  8. ^ "Приоритет оператора C ++ - cppreference.com". en.cppreference.com. Получено 16 июля 2019.
  9. ^ "Приоритет оператора C - cppreference.com". en.cppreference.com. Получено 10 апреля 2020.
  10. ^ «Действительно ли тернарный оператор C / C ++ имеет тот же приоритет, что и операторы присваивания?». Переполнение стека. Получено 22 сентября 2019.
  11. ^ «Другие операторы - cppreference.com». en.cppreference.com. Получено 10 апреля 2020.
  12. ^ "c ++ - Как работает оператор запятая". Переполнение стека. Получено 1 апреля 2020.
  13. ^ C история § Неонатальный C, Bell labs.
  14. ^ "Re ^ 10: следующий без условия". www.perlmonks.org. Получено 23 марта 2018.
  15. ^ ISO / IEC 14882: 1998 (E) Язык программирования C ++. open-std.org - Комитет по стандартам C ++. 1 сентября 1998. С. 40–41.

внешняя ссылка