Оператор (компьютерное программирование) - Operator (computer programming)

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

Общие простые примеры включают арифметику (например, сложение с +), сравнение (например, « больше чем » с >) и логические операции (например AND, также написанные &&на некоторых языках). Более сложные примеры включают присвоение (обычно =или :=), доступ к полю в записи или объекте (обычно .) и оператор разрешения области (часто ::или .). Языки обычно определяют набор встроенных операторов и в некоторых случаях позволяют пользователям добавлять новые значения к существующим операторам или даже определять полностью новые операторы.

Синтаксис

Синтаксически операторы обычно отличаются от функций . В большинстве языков функции можно рассматривать как особую форму префиксного оператора с фиксированным уровнем приоритета и ассоциативностью, часто с обязательными круглыми скобками, например Func(a)(или (Func a)в Лиспе ). Большинство языков поддерживают функции, определяемые программистом, но не могут на самом деле утверждать, что поддерживают операторы, определяемые программистом, если только они не имеют более чем префиксную нотацию и более одного уровня приоритета. Семантически операторы можно рассматривать как особую форму функции с другой нотацией вызова и ограниченным числом параметров (обычно 1 или 2).

Положение оператора относительно его операндов может быть префиксным , инфиксным или постфиксным , а синтаксис выражения, включающего оператор, зависит от его арности (количества операндов ), приоритета и (если применимо) ассоциативности . Большинство языков программирования поддерживают бинарные операторы и несколько унарных операторов , при этом некоторые из них поддерживают больше операндов, например, оператор ?: В C, который является троичным. Существуют префиксные унарные операторы, такие как унарный минус -x, и постфиксные унарные операторы, такие как постинкремент x++ ; а бинарные операции - это инфиксные, например x + yили x = y. Инфиксные операции высшей арности требуют дополнительных символов, таких как тройной оператор  ?: В C, написанном , как a ? b : c- на самом деле, так как это единственный общий пример, часто упоминаются как в тройном операторе. Однако префиксные и постфиксные операции могут поддерживать любую желаемую арность, например 1 2 3 4 +.

Иногда части языка могут быть описаны как операторы «исправления совпадений» или «исправления ошибок», чтобы упростить описание или реализацию языка. Оператор циркумфикса состоит из двух или более частей, в которые входят его операнды. Операторы Circumfix имеют наивысший приоритет, их содержимое оценивается, а результирующее значение используется в окружающем выражении. Самым знакомым оператором циркумфикса являются упомянутые выше круглые скобки, используемые для указания, какие части выражения должны быть вычислены раньше других. Другой пример из физики является скалярное произведение обозначения Дирака Бра и кет . Операторы Circumfix особенно полезны для обозначения операций, в которых задействовано много или различное количество операндов.

Спецификация языка будет определять синтаксис поддерживаемых им операторов, в то время как языки, такие как Prolog, которые поддерживают операторы, определяемые программистом, требуют, чтобы синтаксис был определен программистом.

Семантика

Семантика операторов особенно зависит от значения, стратегии оценки и режима передачи аргументов (например, логического замыкания). Проще говоря, выражение, включающее оператор, каким-то образом оценивается, и результирующее значение может быть просто значением (r-значением) или может быть объектом, допускающим присваивание (l-значение).

В простых случаях это идентично обычным вызовам функций; например, добавление , x + yкак правило , эквивалентно вызову функции add(x, y)и менее чем по сравнению x < yс lt(x, y), а это означает , что аргументы вычисляются в их обычном способе, то некоторая функция вычисляется и результат возвращается как значение. Однако семантика может существенно отличаться. Например, при назначении a = bцель aне оценивается, но вместо этого ее местоположение (адрес) используется для хранения значения b-, соответствующего семантике вызова по ссылке . Кроме того, присвоение может быть выражением (без значения) или выражением (значением), причем само значение может быть либо r-значением (просто значением), либо l-значением (которое может быть присвоено). Другой пример - оператор разрешения области видимости  :: и оператор доступа к элементу. (как в Foo::Barили a.b) оперируют не значениями, а именами , по сути семантикой вызова по имени , а их значением является имя.

Использование l-значений в качестве операндов операторов особенно заметно в унарных операторах увеличения и уменьшения . В C, например, следующий оператор является допустимым и четко определенным и зависит от того факта, что индексирование массива возвращает l-значение:

x = ++a[i];

Важное использование - это когда левоассоциативный бинарный оператор изменяет свой левый аргумент (или производит побочный эффект), а затем оценивает этот аргумент как l-значение. Это позволяет последовательность операторов, влияющих на исходный аргумент, обеспечивая плавный интерфейс , похожий на каскадирование методов . Типичным примером является <<оператор в iostreamбиблиотеке C ++ , который обеспечивает плавный вывод, как показано ниже:

cout << "Hello" << " " << "world!" << endl;

Пользовательские операторы

Язык может содержать фиксированное количество встроенных операторов (например, +, -, *, <, <=,!, = И т. Д. В C и C ++ , PHP ) или он может разрешать создание операторов, определяемых программистом. (например, Prolog , Seed7 , F # , OCaml , Haskell ). Некоторые языки программирования ограничивают символы операторов специальными символами, такими как + или : =, в то время как другие допускают также такие имена, как div(например, Паскаль ).

Большинство языков имеют встроенный набор операторов, но не допускают операторов, определяемых пользователем, поскольку это значительно усложняет синтаксический анализ. Многие языки позволяют использовать операторы только для встроенных типов, но другие позволяют использовать существующие операторы для типов, определяемых пользователем; это известно как перегрузка оператора . Однако некоторые языки позволяют определять новые операторы либо во время компиляции, либо во время выполнения. Это может включать метапрограммирование (определение операторов на отдельном языке) или внутри самого языка. Определение новых операторов, особенно определение времени выполнения, часто делает невозможным правильный статический анализ программ, поскольку синтаксис языка может быть полным по Тьюрингу, поэтому даже построение синтаксического дерева может потребовать решения проблемы остановки, что невозможно. Это происходит , например, с Perl и некоторыми диалектами Lisp .

Примеры

Типичными примерами, которые различаются синтаксически, являются математические арифметические операции , например, ">" вместо " больше, чем ", с именами, которые часто выходят за пределы набора идентификаторов функций языка и вызываются с синтаксисом, отличным от синтаксиса языка для вызова функций. Как функция, "больше чем" обычно будет называться идентификатором, например gtили, greater_thanи вызываться как функция, как gt(x, y). Вместо этого операция использует специальный символ >(который токенизируется отдельно во время лексического анализа ) и инфиксную нотацию, как x > y.

Распространенными примерами, которые отличаются семантически (режимом передачи аргументов), являются логические операции, которые часто включают оценку короткого замыкания : например, замыкающее соединение (X AND Y), которое оценивает только более поздние аргументы, если более ранние не являются ложными, на языке с строгие функции вызова по значению. Вместо этого он ведет себя аналогично if / then / else.

Менее распространенные операторы включают:

Компиляция

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

Перегрузка оператора

В некоторых языках программирования оператор может быть специальным полиморфным , то есть иметь определения для более чем одного типа данных (например, в Java, где оператор + используется как для сложения чисел, так и для конкатенации строк). Такой оператор называется перегруженным . В языках, которые поддерживают перегрузку операторов программистом (например, C ++ ), но имеют ограниченный набор операторов, перегрузка операторов часто используется для определения настраиваемого использования операторов.

В этом примере IF ORDER_DATE > "12/31/2011" AND ORDER_DATE < "01/01/2013" THEN CONTINUE ELSE STOPиспользуются следующие операторы: «>» (больше), «И» и «<» (меньше).

Принуждение операнда

Некоторые языки также позволяют операнды оператора быть неявно преобразованы или принуждением , в подходящие типы данных для операции происходит. Например, в Perl правила принуждения приводят к 12 + "3.14"получению результата 15.14. "3.14"Перед добавлением текст преобразуется в число 3,14. Кроме того, 12является целым числом и 3.14представляет собой либо число с плавающей запятой, либо число с фиксированной запятой (число, в котором есть десятичный разряд), поэтому целое число затем преобразуется в число с плавающей запятой или с фиксированной запятой соответственно.

JavaScript следует противоположным правилам - найдя такое же выражение выше, он преобразует целое число 12в строку "12", а затем объединит два операнда в форму "123.14".

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

Возможности оператора в языках программирования

В следующей таблице показаны функции оператора на нескольких языках программирования:

Язык программирования Символы операторов без цифр и букв Буквенно-цифровые символы операторов Приставка Инфикс Постфикс Приоритет Ассоциативность Перегрузка Перегрузка, определяемая программистом Символы операторов, определяемые программистом
АЛГОЛ 68 + * ** * /%% *% × - + <<=> => = / = & -: = +: = *: = /: =%: =% *: = + =:: =:: / знак равно

(Все операторы имеют буквенно-цифровые эквиваленты жирным шрифтом , см. Следующий столбец. У некоторых есть эквиваленты, отличные от ASCII , см. Ниже.) ¬ + × ⊥ ↑ ↓ ⌊ ⌈ × ÷ ÷ × ÷ * □ ≤ ≥ ≠ ∧ ∨ ×: = ÷: = ÷ × : = ÷ *: =% ×: =: ≠:

не абс Arg бен entier лэн уровень нечетная магнезии круглой сократить я SHL SHR вверх вниз LWB УПБ LT ле ге GT экв пе и или более моды эль minusab plusab timesab divab overab modab plusto есть разве да да Нет Да (префиксные операторы всегда имеют приоритет 10) Инфиксные операторы ассоциативны слева, префиксные операторы ассоциативны справа да да да
APL + - × ÷ ⌈ ⌊ * ⍟ | ! ○ ~ ∨ ∧ ⍱ ⍲ <≤ = ≥> ≠. @ ≡ ≢ ⍴, ⍪ ⍳ ↑ ↓? ⍒ ⍋ ⍉ ⌽ ⊖ ∊ ⌹ ⊂ ⊃ ∪ ∩ ⍷ ⌷ ∘ → ← / ⌿ \ ⍀ ¨ ⍣ & ⍨ ⌶ ⊣ ⊢ ⍠ ⍤ ⌺ ⍸ Буквенно-цифровые символы должны содержать ⎕ перед ключевым словом. Да (только функции первого порядка) да Да (только функции высшего порядка) Функции высшего порядка предшествуют функциям первого порядка Функции высшего порядка левоассоциативны, функции первого порядка - правоассоциативны. да да Да (только буквенно-цифровые)
C () [] ->. ! ~ ++ - + - * & /% << >> <<=>> = ==! = ^ | && || ?: = + = - = * = / =% = & = ^ = размер да да да да да да Нет Нет
C ++ ( подробнее ) SizeOf TypeID нового удаления броска decltype static_cast динамического литой reinterpret_cast const_cast да да да да да да да Нет
C # ( подробнее ) То же, что C / C ++, вместе с ?.  ? [] ?? sizeof nameof new stackalloc await throw checked unchecked является делегатом по умолчанию true false
LINQ : from select where group ... by group ... by ... into join ... in ... on ... equals join ... в ... на ... равно ... в порядке по порядку ... по убыванию
Roslyn -only : __makeref __refvalue __reftype
да да да да да да да Нет
Джава То же, что C / C ++ новый бросок instanceof да да да да да да Нет Нет
Эйфелева [] + - * / // = / = не и или подразумевает «а потом» «или еще» да да Нет да да Нет да да
Haskell + - * / ^ ^^ ** ​​== / => <> = <= && || >> = >> $ $! . ++ !! : Еще много в общих библиотеках Имя функции должно быть заключено в обратные кавычки. да да Нет да да Да, используя классы типов да
Паскаль * / + - = <> <> <=> =: = не мод div и или в да да Нет да да да Нет Нет
Perl -> ++ - **! ~ \ + -. = ~! ~ * /% <> <=> = ==! = <=> ~~ & | ^ && || ' print sort chmod chdir rand and or not xor lt gt le ge eq ne cmp x да да да да да да да Нет
Раку ++ - **! ~ ~~ * / + -. <> <=> = ==! = <=> & | ^ && || // print sort chmod chdir rand and or not xor lt gt le ge eq ne leg cmp x xx да да да да да да да да
PHP [] ** ++ - ~ @! * /% + -. << >> <<=>> = ==! = ===! == <> <=> & ^ | && || ?? ?: = + = - = * = ** = / =. =% = & = | = ^ = << = >> = clone new unset print echo isset instanceof and or xor да да да да да Нет Нет Нет
PL / I () -> + - * / **> ¬>> = = ¬ = <= <¬ <¬ & | || да да Нет да да Нет Нет Нет
Пролог : -? -; ,. = .. = \ = <= <> => == \ == - + / * шпион носпи не мод да да да да да Нет Нет да
Семя7 {} [] -> **! + - * / << >> &> <| = <>>> = <<= <&: = +: = -: = *: = /: = <<: = >>: = &: = @: = конв varConv синтаксического анализа Призывание ДИВ бэр mdiv мод раз сть в не и или цифр LPAD RPAD lpad0 да да да да да да да да
Болтовня (да - до двух символов) После ключевого слова буквенно-цифровым символам необходимо двоеточие. Нет да да Нет Нет да да да
Быстрый Любая строка символов Юникода, кроме . , в том числе ! ~ + - * /% = + = - = * = / =% & + & - & * = & + = & - = & * && || << >> & | ^ ==! = <<=>> = ?? ... .. < в стандартной библиотеке это как как? да да да Да (определяется как частичный порядок в группах приоритета) Да (определяется как часть групп приоритета) да да да
Visual Basic .NET (). ! ? ()?. ?! + - * / \ & << >> <<=>> = ^ <> = + = - = * = / = \ = & = ^ = << = >> = Новый мод Await Like Is Not Not Not And AndAlso или OrElse Xor If (..., ...) If (..., ..., ...) GetXmlNamespace (...) GetType (...) NameOf ( ...) TypeOf ... Is TypeOf ... IsNot DirectCast (..., ...) TryCast (..., ...) CType (..., ...) CBool ​​(...) CByte (...) CChar (...) CDate (...) CDec (...) CDbl (...) CInt (...) CLng (...) CObj (...) CSByte ( ...) CShort (...) CSng (...) CStr (...) CUInt (...) CULng (...) CUShort (...)
LINQ : From Aggregate ... Into Select Distinct Где <Сортировать по> ... [По возрастанию | По убыванию] Взять <Продолжить> Пропустить <Пропустить> Разрешить группе ... По ... Присоединиться ... При <Присоединиться к группе ... На ... В>
да да да да да да да Нет

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

Примечания

использованная литература