Операторы инкремента/декремента

RemarksRemarks

В C++ доступны префиксные и постфиксные операции инкремента и декремента. В этом разделе описываются только их постфиксные формы.C++ provides prefix and postfix increment and decrement operators; this section describes only the postfix increment and decrement operators. (Дополнительные сведения см. в разделе Операторы инкремента и декремента префикса.) Разница между ними заключается в том, что в постфиксной нотации оператор появляется после постфиксного выражения, тогда как в нотации префикса оператор появляется перед выражением.(For more information, see Prefix Increment and Decrement Operators.) The difference between the two is that in the postfix notation, the operator appears after postfix-expression, whereas in the prefix notation, the operator appears before expression. В следующем примере представлен постфиксный оператор инкремента:The following example shows a postfix-increment operator:

Результатом применения оператора постфиксного инкремента ( ++ ) является то, что значение операнда увеличивается на одну единицу соответствующего типа.The effect of applying the postfix increment operator (++) is that the operand’s value is increased by one unit of the appropriate type. Аналогичным образом, результат применения постфиксного оператора декремента ( — ) заключается в том, что значение операнда уменьшается на одну единицу соответствующего типа.Similarly, the effect of applying the postfix decrement operator (—) is that the operand’s value is decreased by one unit of the appropriate type.

Важно отметить, что постфиксное выражение инкремента или декремента вычисляет значение выражения до применения соответствующего оператора.It is important to note that a postfix increment or decrement expression evaluates to the value of the expression prior to application of the respective operator. Операция инкремента или декремента выполняется после вычисления операнда.The increment or decrement operation occurs after the operand is evaluated

Эта особенность возникает, только когда постфиксная операция инкремента или декремента выполняется в контексте выражения.This issue arises only when the postfix increment or decrement operation occurs in the context of a larger expression.

Если же постфиксный оператор применяется к аргументу функции, то инкремент или декремент значения аргумента необязательно будет выполнен до его передачи в функцию.When a postfix operator is applied to a function argument, the value of the argument is not guaranteed to be incremented or decremented before it is passed to the function. Дополнительные сведения см. в разделе 1.9.17 стандарта C++.See section 1.9.17 in the C++ standard for more information.

Применение постфиксного оператора инкремента к указателю на массив объектов типа фактически добавляет четыре к внутреннему представлению указателя.Applying the postfix increment operator to a pointer to an array of objects of type actually adds four to the internal representation of the pointer. Это поведение приводит к тому, что указатель, который ранее ссылался на n-й элемент массива, ссылается на элемент (n+ 1) TH.This behavior causes the pointer, which previously referred to the nth element of the array, to refer to the (n+1)th element.

Операнды для постфиксного инкремента и постфиксных операторов декремента должны быть изменяемыми (а не ) l-значениями арифметического типа.The operands to postfix increment and postfix decrement operators must be modifiable (not ) l-values of arithmetic or pointer type. Тип результата такой же, как у постфиксного выражения, но больше не является l-значением.The type of the result is the same as that of the postfix-expression, but it is no longer an l-value.

Visual Studio 2017 версии 15,3 и более поздних версий (доступно с /std: c++ 17): операнд постфиксного оператора инкремента или декремента не может иметь тип .Visual Studio 2017 version 15.3 and later (available with /std:c++17): The operand of a postfix increment or decrement operator may not be of type .

Ниже показан пример постфиксного оператора инкремента.The following code illustrates the postfix increment operator:

Постфиксные операции инкремента или декремента для типов перечисления не поддерживаются:Postincrement and postdecrement operations on enumerated types are not supported:

Приоритет и ассоциативность операторовOperator precedence and associativity

В следующем списке перечислены арифметические операторы в порядке убывания приоритета:The following list orders arithmetic operators starting from the highest precedence to the lowest:

  • Постфиксный инкремент и декремент Postfix increment and decrement operators
  • Префиксный инкремент и декремент , унарные операторы и Prefix increment and decrement and unary and operators
  • Мультипликативные операторы , , и Multiplicative , , and operators
  • Аддитивные операторы и Additive and operators

Бинарные арифметические операторы имеют левую ассоциативность.Binary arithmetic operators are left-associative. То есть операторы с одинаковым приоритетом вычисляются в направлении слева направо.That is, operators with the same precedence level are evaluated from left to right.

Порядок вычисления, определяемый приоритетом и ассоциативностью операторов, можно изменить с помощью скобок ().Use parentheses, , to change the order of evaluation imposed by operator precedence and associativity.

Полный список операторов C#, упорядоченный по уровню приоритета, можно найти в разделе статьи Операторы C#.For the complete list of C# operators ordered by precedence level, see the section of the C# operators article.

Арифметические операции языка C#

Последнее обновление: 19.06.2017

В C# используется большинство операций, которые применяются и в других языках программирования. Операции представляют определенные действия над операндами —
участниками операции. В качестве операнда может выступать переменной или какое-либо значение (например, число).
Операции бывают унарными (выполняются над одним операндом), бинарными — над двумя операндами и тернарными — выполняются над тремя операндами. Рассмотрим все виды операций.

Бинарные арифметические операции:

  • +

    Операция сложения двух чисел:

    int x = 10;
    int z = x + 12; // 22
    
  • Операция вычитания двух чисел:

    int x = 10;
    int z = x - 6; // 4
    
  • *

    Операция умножения двух чисел:

    int x = 10;
    int z = x * 5; // 50
    
  • операция деления двух чисел:

    int x = 10;
    int z = x / 5; // 2
    
    double a = 10;
    double b = 3;
    double c = a / b; // 3.33333333
    

    При делении стоит учитывать, что если оба операнда представляют целые числа, то результат также будет округляться до целого числа:

    double z = 10 /  4; //результат равен 2

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

    Для выхода из этой ситуации необходимо определять литералы или переменные, участвующие в операции, именно как типы double или float:

    double z = 10.0 /  4.0; //результат равен 2.5
  • %

    Операция получение остатка от целочисленного деления двух чисел:

    double x = 10.0;
    double z = x % 4.0; //результат равен 2
    

Также есть ряд унарных операций, в которых принимает участие один операнд:

++
Операция инкремента
Инкремент бывает префиксным: ++x — сначала значение переменной x увеличивается на 1,
а потом ее значение возвращается в качестве результата операции.

int x1 = 5;
int z1 = ++x1; // z1=6; x1=6
Console.WriteLine($"{x1} - {z1}");

int x2 = 5;
int z2 = x2++; // z2=5; x2=6
Console.WriteLine($"{x2} - {z2}");

Операция декремента или уменьшения значения на единицу. Также существует префиксная форма декремента () и
постфиксная ().

int x1 = 5;
int z1 = --x1; // z1=4; x1=4
Console.WriteLine($"{x1} - {z1}");

int x2 = 5;
int z2 = x2--; // z2=5; x2=4
Console.WriteLine($"{x2} - {z2}");

При выполнении сразу нескольких арифметических операций следует учитывать порядок их выполнения. Приоритет операций от наивысшего к низшему:

  1. Инкремент, декремент

  2. Умножение, деление, получение остатка

  3. Сложение, вычитание

Для изменения порядка следования операций применяются скобки.

Рассмотрим набор операций:

int a = 3;
int b = 5;
int c = 40;
int d = c---b*a;    // a=3  b=5  c=39  d=25
Console.WriteLine($"a={a}  b={b}  c={c}  d={d}");

Здесь мы имеем дело с тремя операциями: декремент, вычитание и умножение. Сначала выполняется декремент переменной c, затем умножение b*a, и в конце вычитание. То есть фактически набор операций выглядел так:

int d = (c--)-(b*a);

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

int a = 3;
int b = 5;
int c = 40;
int d = (c-(--b))*a;    // a=3  b=4  c=40  d=108
Console.WriteLine($"a={a}  b={b}  c={c}  d={d}");

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

Как выше было отмечено, операции умножения и деления имеют один и тот же приоритет, но какой тогда результат будет в выражении:

int x = 10 / 5 * 2;

Стоит нам трактовать это выражение как или как ? Ведь в зависимости от трактовки
мы получим разные результаты.

Когда операции имеют один и тот же приоритет, порядок вычисления определяется ассоциативностью операторов. В зависимости от ассоциативности
есть два типа операторов:

  • Левоассоциативные операторы, которые выполняются слева направо

  • Правоассоциативные операторы, которые выполняются справа налево

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

НазадВперед

Инкремент и декремент в C#

Создадим пример, где покажем различие между префиксными и постфиксными инкрементами.

using System;
public class Program
{
public static void Main()
{
int x = 10;
Console.WriteLine(x++);
Console.WriteLine(x * 2);
Console.ReadLine();
}
}

1
2
3
4
5
6
7
8
9
10
11

using System;

publicclassProgram

{

publicstaticvoidMain()

{

intx=10;

Console.WriteLine(x++);

Console.WriteLine(x *2);

Console.ReadLine();

}

}

В этом примере мы создали переменную x, равную 10. Затем мы выводим постинкремент этого x на консоль, а также выводим выражение, где x умножается на 2. Запустим программу и посмотрим на результат:

Итак, сначала нам вывелся исходный x без прибавления к нему единицы. Почему так? Мы уже говорили, что при постинкременте значение переменной сначала будет использоваться в выражении, где необходима эта переменная, а только потом увеличится на 1. Данным «выражением» стал как раз метод Console.WriteLine, который вывел нашу переменную. После этого инкремент сработал, x увеличился на единицу, а затем сработал второй метод вывода, где x увеличивался в два раза. Именно поэтому во второй строке у нас получилось 22.
Теперь давайте поменяем инкремент на префиксный и посмотрим, что изменится.

using System;
public class Program
{
public static void Main()
{
int x = 10;
Console.WriteLine(++x);
Console.WriteLine(x * 2);
Console.ReadLine();
}
}

1
2
3
4
5
6
7
8
9
10
11

using System;

publicclassProgram

{

publicstaticvoidMain()

{

intx=10;

Console.WriteLine(++x);

Console.WriteLine(x *2);

Console.ReadLine();

}

}

Результат такой:

Как уже можно понять, значение переменной x сразу же увеличилось на 1, поэтому при выводе в первой строке у нас получилось 11, а не 10. Вторая строка не изменилась, так как в любом случае мы умножаем 11 на 2.

С декрементами всё обстоит точно так же:

Программа с постдекрементом

Программа с предекрементом

Скачать исходник

Ниже мы приведём листинги тех же примеров на других языках программирования. Соответственно, результаты будут такие же, как и в описанных выше программах.

Инкремент и декремент в С++

Постинкремент в С++

#include <iostream>
using namespace std;
int main() {
int x=10;
cout << x++ << ‘\n’;
cout << x * 2;
return 0;
}

1
2
3
4
5
6
7
8

#include <iostream>

using namespacestd;

intmain(){

intx=10;

cout<<x++<<‘\n’;

cout<<x *2;

return;

}

Преинкремент в С++

#include <iostream>
using namespace std;
int main() {
int x=10;
cout << ++x << ‘\n’;
cout << x * 2;
return 0;
}

1
2
3
4
5
6
7
8

#include <iostream>

using namespacestd;

intmain(){

intx=10;

cout<<++x<<‘\n’;

cout<<x *2;

return;

}

Постдекремент в С++

#include <iostream>
using namespace std;
int main() {
int x=10;
cout << x— << ‘\n’;
cout << x * 2;
return 0;
}

1
2
3
4
5
6
7
8

#include <iostream>

using namespacestd;

intmain(){

intx=10;

cout<<x—<<‘\n’;

cout<<x *2;

return;

}

Предекремент в С++

#include <iostream>
using namespace std;
int main() {
int x=10;
cout << —x << ‘\n’;
cout << x * 2;
return 0;
}

1
2
3
4
5
6
7
8

#include <iostream>

using namespacestd;

intmain(){

intx=10;

cout<<—x<<‘\n’;

cout<<x *2;

return;

}

Спасибо за прочтение!

Поделиться в соц. сетях:

Ошибки округленияRound-off errors

Из-за общих ограничений, касающихся представления вещественных чисел в форме с плавающей запятой и арифметических операций с плавающей запятой, при вычислениях с использованием типов с плавающей запятой могут возникать ошибки округления.Because of general limitations of the floating-point representation of real numbers and floating-point arithmetic, round-off errors might occur in calculations with floating-point types. То есть полученный результат выражения может отличаться от ожидаемого математического результата.That is, the produced result of an expression might differ from the expected mathematical result. В следующем примере показано несколько таких случаев:The following example demonstrates several such cases:

См. заметки в справочной документации по , и .For more information, see remarks at the , , or reference pages.

Придумывайте правильные имена

В разговоре о переменных необходимо упомянуть, что есть ещё одна чрезвычайно важная вещь.

Название переменной должно иметь ясный и понятный смысл, говорить о том, какие данные в ней хранятся.

Именование переменных – это один из самых важных и сложных навыков в программировании. Быстрый взгляд на имена переменных может показать, какой код был написан новичком, а какой – опытным разработчиком.

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

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

Несколько хороших правил:

  • Используйте легко читаемые имена, такие как или .
  • Избегайте использования аббревиатур или коротких имён, таких как , , , за исключением тех случаев, когда вы точно знаете, что так нужно.
  • Делайте имена максимально описательными и лаконичными. Примеры плохих имён: и . Такие имена ничего не говорят. Их можно использовать только в том случае, если из контекста кода очевидно, какие данные хранит переменная.
  • Договоритесь с вашей командой об используемых терминах. Если посетитель сайта называется «user», тогда мы должны называть связанные с ним переменные или , а не, к примеру, или .

Звучит просто? Действительно, это так, но на практике для создания описательных и кратких имён переменных зачастую требуется подумать. Действуйте.

Повторно использовать или создавать новую переменную?

И последняя заметка. Есть ленивые программисты, которые вместо объявления новых переменных повторно используют существующие.

В результате их переменные похожи на коробки, в которые люди бросают разные предметы, не меняя на них этикетки. Что сейчас находится внутри коробки? Кто знает? Нам необходимо подойти поближе и проверить.

Такие программисты немного экономят на объявлении переменных, но теряют в десять раз больше при отладке.

Дополнительная переменная – это добро, а не зло.

Современные JavaScript-минификаторы и браузеры оптимизируют код достаточно хорошо, поэтому он не создаёт проблем с производительностью. Использование разных переменных для разных значений может даже помочь движку оптимизировать ваш код.

Инкремент и декремент в Java

Постинкремент в Java

public class Prog {

public static void main(String []args){
int x = 10;
System.out.println(x++);
System.out.println(x * 2);
}
}

1
2
3
4
5
6
7
8

publicclassProg{

publicstaticvoidmain(Stringargs){

intx=10;

System.out.println(x++);

System.out.println(x *2);

}

}

Преинкремент в Java

public class Prog {

public static void main(String []args){
int x = 10;
System.out.println(++x);
System.out.println(x * 2);
}
}

1
2
3
4
5
6
7
8

publicclassProg{

publicstaticvoidmain(Stringargs){

intx=10;

System.out.println(++x);

System.out.println(x *2);

}

}

Постдекремент в Java

public class Prog {

public static void main(String []args){
int x = 10;
System.out.println(x—);
System.out.println(x * 2);
}
}

1
2
3
4
5
6
7
8

publicclassProg{

publicstaticvoidmain(Stringargs){

intx=10;

System.out.println(x—);

System.out.println(x *2);

}

}

Предекремент в Java

public class Prog {

public static void main(String []args){
int x = 10;
System.out.println(—x);
System.out.println(x * 2);
}
}

1
2
3
4
5
6
7
8

publicclassProg{

publicstaticvoidmain(Stringargs){

intx=10;

System.out.println(—x);

System.out.println(x *2);

}

}

Допустимые имена для переменных

Идентификаторы переменных могут содержать в себе:

  • латинские буквы;
  • цифры;
  • знак нижнего подчёркивания.

При этом название не может начинаться с цифр. Примеры названий:

  • age;
  • name;
  • _sum;
  • first_name;
  • a1;
  • a2;
  • a_5.

Все идентификаторы регистрозависимы. Это значит, что name и Name — разные переменные.

Рекомендуется давать именам простые названия на английском языке, чтобы код был понятен и вам, и другим людям. Например:

  • price, а не stoimost;
  • currentId, а не pupa;
  • carsCount, а не lupa и так далее.

Если название должно состоять из нескольких слов, то рекомендуется использовать camelCase (с англ. «верблюжий регистр»): первое слово пишется со строчной буквы, а каждое последующее — с заглавной.

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

  • рассматривают исходные числовые значения как поля битов и выполняют над ними следующие действия:
  • установка бита в i-ой позиции поля результата в , если оба бита в i-ых позициях операндов равны , или в в противном случае – («»);
  • установка бита в i-ой позиции поля результата в , если хотя бы один бит в i-ых позициях операндов равен , или в в противном случае – («»);
  • установка бита в i-ой позиции поля результата в , если биты в i-ых позициях операндов не равны друг другу, или в в противном случае – («»);
  • сдвиг влево битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом не меняется) – «»;
  • сдвиг вправо битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом не меняется) – «»;
  • сдвиг вправо битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом также сдвигается) – «».

Примеры побитовых операций:

  1. Побитовое И

  2. Побитовое ИЛИ

  3. Побитовое исключающее ИЛИ

  4. Сдвиг влево с учетом знака

  5. Сдвиг вправо с учетом знака

  6. Сдвиг вправо без учета знака

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *