Я провел несколько тестов в 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
Я не понимаю, почему с == 128! Насколько я понимаю, в обоих дополнениях b + a все еще считаются дополнением 2 со знаком 8 бит переменные. Таким образом, результатом является переполнение, то есть -128. После этого, затем результат повышается до 16-битного со знаком int для первой операции присваивания, и c все равно должен получить 16-битное значение -128. Правильно ли мое понимание? Стандарт с ++ немного сложен для чтения. Кажется, в главе 4 говорится об интегральном продвижении, но я не могу найти ничего, связанного с этим конкретным примером.
Насколько я понимаю, в обоих дополнениях b + a все еще считаются сложением 8-битных переменных с 2 знаками. Таким образом, результатом является переполнение, то есть -128.
Нет, продвижение происходит до +
оценивается, а не после него. Добавление происходит, когда оба a
а также b
положительны. Оба числа повышены до int
s для сложения, добавляются как два положительных числа, а затем преобразуются в 16-битное короткое число. Ни в одной точке процесса результат не становится отрицательным из-за переполнения, следовательно, конечный результат равен 128.
Возможно, это имеет смысл: поведение a
а также b
соответствует математике двух чисел в математике, что делает его более понятным для практиков языка.
1 Значение типа integer, отличное от bool, char16_t, char32_t или wchar_t, чей ранг целочисленного преобразования (4.13) меньше ранга int, может быть преобразовано в значение типа int, если int может представлять все значения типа источника ; в противном случае исходное значение prvalue может быть преобразовано в значение типа unsigned int. [§ 4.5]
В этом заявлении
__int16 c=b+a;
Во-первых, все
char
а такжеshort int
значения автоматически повышаются доint
, Этот процесс называется интегральное продвижение. Затем все операнды преобразуются в тип самого большого операнда, который называется продвижение типа. [Герберт Шильдт]
ценности переменных 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
имеет).