Арифметика C++ со Смешанными Целыми Типами, вызывающая Переполнение
-
21-12-2019 - |
Вопрос
Я провел несколько тестов в VC++2010, смешивая операнды разных размеров, которые вызывают переполнение при операции добавления:
int _tmain(int argc, _TCHAR* argv[])
{
__int8 a=127;
__int8 b=1;
__int16 c=b+a;
__int8 d=b+a;
printf("c=%d,d=%d\n",c,d);
return 0;
}
//result is: c=128, d=-128
Я не понимаю, почему c==128!Насколько я понимаю, в обоих дополнениях b + a по-прежнему считаются добавлением 2 подписанных 8 бит переменные.Таким образом, результатом является переполнение, т.е.-128. После этого, затем результат преобразуется в 16-битный signed int для первой операции присваивания, и c все равно должен получить 16-битное значение -128.Правильно ли я понимаю?Стандарт c++ немного сложен для чтения.В главе 4, кажется, говорится о комплексном продвижении, но я не могу найти ничего, связанного с этим конкретным примером.
Решение
Насколько я понимаю, в обоих дополнениях b +a по-прежнему считаются добавлением 2 8-битных переменных со знаком.Таким образом, результатом является переполнение, т.е.-128.
Нет, повышение по службе происходит до того, как +
оценивается, а не после него.Сложение происходит, когда оба a
и b
являются положительными.Оба номера повышены до int
s для сложения, добавляется в виде двух положительных чисел, а затем преобразуется в 16-битное короткое значение.Ни на одном этапе процесса результат не становится отрицательным из-за переполнения, следовательно, конечный результат равен 128.
Возможно, в этом есть смысл:поведение a
и b
соответствует значению двух чисел в математике, что делает его более интуитивным для практикующих язык.
Другие советы
Это неотъемлемое продвижение.
1 Prvalue целочисленного типа, отличного от bool, char16_t, char32_t или wchar_t, ранг преобразования целого числа которого (4.13) меньше ранга int, может быть преобразовано в prvalue типа int, если int может представлять все значения исходного типа;в противном случае исходное prvalue может быть преобразовано в prvalue типа unsigned int.[§ 4.5]
В этом заявлении
__int16 c=b+a;
Во-первых, все
char
иshort int
значения автоматически повышаются доint
.Этот процесс называется комплексное продвижение.Далее все операнды преобразуются до типа самого большого операнда, который вызывается тип продвижения по службе.[Herbert Schildt]
Тот Самый ценности переменных b
и a
будет повышен до int
и затем к ним применяется операция.
В двухкомпонентном целочисленном представлении значение со знаком представляется путем установки старшего бита.Это позволяет машине складывать и вычитать двоичные целые числа с помощью одних и тех же инструкций, независимо от того, имеет ли целое число знак.
a = 127 == 0x7F == 0b01111111
+ b = 1 == 0x01 == 0b00000001
-------------------------------
c = 128 == 0x80 == 0b10000000
d =-128 == 0x80 == 0b10000000
Переменные c
и d
могут иметь разные типы, но разные типы целых чисел - это просто разные интерпретации одного двоичного значения.Как вы можете видеть выше, двоичное значение прекрасно укладывается в 8 бит.Поскольку стандарт требует, чтобы члены математического выражения были расширены до размера машинного слова нулем или знаком до выполняется любая математика, и ни один из операндов не будет расширен знаком, результат всегда равен 0b10000000
независимо от того, к какому типу относятся операнды.
Таким образом, разница между результатами заключается в том, что для 16-битного целого числа знаковый бит равен 0b1000000000000000
(который a+b
не имеет), а для 8-битного целого числа знаковый бит равен 0b10000000
(который a+b
действительно имеет).