что происходит, когда я смешиваю подписанные и неподписанные типы?

Я изучаю язык C ++ и у меня есть некоторые сомнения по поводу преобразования типов, не могли бы вы объяснить, что происходит в выражении, подобном этому:

unsigned int u = 10;
int a = -42;
std::cout << u - a << std::endl;

Здесь я знаю, что результатом будет 52, если я приму правила, когда у нас есть два математических оператора. Но мне интересно, что произойдет, когда компилятор для преобразования в беззнаковое значение создаст временный тип без знака, что произойдет после? Выражение теперь должно быть 10 -4294967254.

10

Решение

Проще говоря, если вы смешиваете типы одного ранга (в последовательности int, long int, long long int), беззнаковый тип «выигрывает», и вычисления выполняются в пределах этого беззнакового типа. Результат того же типа без знака.

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

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

В вашем случае вы смешали типы одного ранга (int а также unsigned int), что означает, что все выражение оценивается в unsigned int тип. Выражение, как вы правильно сказали, теперь 10 - 4294967254 (для 32 бит int). Типы без знака подчиняются правилам арифметики по модулю 2^32 (4294967296) по модулю. Если вы тщательно рассчитаете результат (который можно выразить арифметически как 10 - 4294967254 + 4294967296) получится как положено 52,

14

Другие решения

1) Из-за стандартных правил продвижения signed тип a повышен до unsigned введите до вычитания. Это продвижение происходит в соответствии с этим правилом (стандарт C ++ 4.7 / 2):

Если тип назначения не подписан, полученное значение является наименьшим
целое число без знака, совпадающее с целым числом источника (по модулю 2n, где n
количество битов, используемых для представления типа без знака).

Алгебраически a становится очень большим положительным числом и, конечно, больше, чем u,

2) u - a является анонимным временным и будет неподписанный тип. (Вы можете проверить это, написав auto t = u - a и проверка типа t в вашем отладчике.) Математически это будет отрицательное число, но при неявном преобразовании в беззнаковый тип вызывается правило циклического переноса, подобное приведенному выше.

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

2

вот код дизассемблирования говорит:

это сначала устанавливает -42 в дополнение и сделать субоперацию. так что результат 10 + 42
0x0000000000400835 <+8>: movl $0xa,-0xc(%rbp)
0x000000000040083c <+15>: movl $0xffffffd6,-0x8(%rbp)
0x0000000000400843 <+22>: mov -0x8(%rbp),%eax
0x0000000000400846 <+25>: mov -0xc(%rbp),%edx
0x0000000000400849 <+28>: sub %eax,%edx
0x000000000040084b <+30>: mov %edx,%eax

-1