Над переменными и литералами мы можем выполнять различные операции.

Базовые математические операции

Начнём с операции сложения, она выглядит так же как и в математике:

int a = 1;
int b = 2;
int c = a + b;
std::cout << c << std::endl;
3

То же самое касается остальных арифметических операций:

int a = 6;
int b = 2;
std::cout << (a + b) << std::endl;
std::cout << (a - b) << std::endl;
std::cout << (a / b) << std::endl;
std::cout << (a * b) << std::endl;
8
4
3
12

Особенности операции сложения

При сложении двух переменных типа char мы выполняем операцию не над символами, а над их числовым представлением:

char a = 'A';
char b = 'B';
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << (int)a << std::endl;
std::cout << (int)b << std::endl;
std::cout << (char)(a+b) << std::endl;
std::cout << (int)(a+b) << std::endl;
A
B
65
66
â
131

Стоит отметить что значение символа â с кодом 131 не гарантированно в этом случае, и зависит от многих факторов таких как кодировка, платформа и знаковость типа char.

При выполнении операции выполняется целочисленное продвижение (integer promotion) или же расширение типа.

Это означает что значения типа char (или других более узких типов - short, bool) неявно преобразуются в значения более широких типов - обычно int или unsigned int, если тип int не способен представить значение.

Типы, которые подвержены целочисленному продвижению: char, signed char, unsigned char, bool, short, unsigned short.

Этот механизм используется в C++ для обеспечения корректности математических операций.

Операция унарного минуса

При такой записи

int x = -5;

знак минус здесь - это оператор унарного минуса, применяемый к литералу 5.

Сначала создаётся литерал 5, затем к нему применяется оператор унарного минуса, который меняет знак значения.

Нужно отметить что это происходит не во время выполнения, а во время компиляции.

В этом вы можете убедиться если напишете эту строчку кода и наведёте курсор на значение -5.

Вы увидите (int)5, это зависит от IDE, но в VS это отображается именно так.

Особенности операции деления

Нужно отметить, что если мы поделим два числа типа int со значениями 1 и 2 то мы получим 0.

int a = 1;
int b = 2;
std::cout << (a / b) << std::endl;
0

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

Если нас это не устраивает и нам дробная часть нужна - необходимо использовать тип, который это делать позволяет, допустим, тип float:

float a = 1;
float b = 2;
std::cout << (a / b) << std::endl;
0.5

Допустим, если мы поделим 5 на 2 мы получим 2 при использовании типа int.

int a = 5;
int b = 2;
std::cout << (a / b) << std::endl;
2

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

Если мы применим операцию деления таким образом:

double x = 7 / 2;
std::cout << x << std::endl;
3

То мы получим неожиданный результат.

Это происходит потому, что сначала выполняется целочисленное деление, а потом его результат конвертируется в double.

double x = 7.0 / 2;
double y = 7.f / 2;
std::cout << x << std::endl;
std::cout << y << std::endl;
3.5
3.5

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

Необходимо это указать явно.

Операция взятия остатка от деления

Отдельно стоит выделить оператор % он позволяет выполнить операцию взятия остатка от деления

int a = 5;
int b = 2;
std::cout << (a % b) << std::endl;
1

Эта операция не часто встречается в привычной математике, но в программировании она бывает очень полезной.

Мы можем применять оператор получения остатка от деления только к целым типам.

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

Я регулярно публикую материал и разборы ситуаций для различных игр, движков, а так же подходов разработки включая Internal, External и DMA.

Эта публикация содержит только часть статьи.

Полные уроки по C++, реверс-инжинирингу и разработке софта вы можете найти тут: