Немного про операции
Операторы строенных типов всегда работают только с одинаковыми типами, если типы разные, то происходит преобразование типов.
Правила преобразования типов:
- Если один из аргументов имеет тип с плавающей точкой, то второй аргумент приводится к этому типу. (double + int => double + double)
- Если оба аргумента имеют тип с плавающей точкой, то выбирается наибольший. (double + float => double + double)
- Если оба аргумента целочисленные, но меньше чем int, то оба аргумента приводятся к типу int. (char + char => int + int)
- Если оба аргумента целочисленные, то выбирается наибольший. (long + int => long + long)
- Если оба аргумента целочисленные и имеют тип одного размера, то предпочтение отдаётся беззнаковому типу. (int + unsigned int => unsigned int + unsigned int)
❗ С unsigned вообще стоит быть очень аккуратным, если значение unsigned будет -1, то значение в результате переполнения станет максимальным, и наоборот если к максимальному значению добавить 1, то значение в результате переполнения станет 0.
#include <limits.h>
unsigned k = -1;
cout << k << " " << UINT_MAX; // 4294967295 4294967295
#include <limits.h>
unsigned k = UINT_MAX;
cout << k+1; // 0
#include <iostream>
int main()
{
std::cout << 7u-13;
// -13 приводится к unsigned => UINT_MAX - 12 => ((2^32)-1) - 12 = 4294967283
// производится сложение 7 + 4294967283 = 4294967290
}