Арифметика C++ со смешанными целочисленными типами, вызывающая переполнение

Я провел несколько тестов в 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 по-прежнему считается добавлением двух подписанных 8-битных переменных. Таким образом, результатом является переполнение, т.е. -128. После этого результат повышается до 16-битного целого числа со знаком для первой операции присваивания, а c все равно должно получить 16-битное значение -128. Правильно ли я понимаю? Стандарт С++ немного сложен для чтения. Глава 4, кажется, говорит о целочисленном расширении, но я не могу найти ничего, связанного с этим конкретным примером.


person JavaMan    schedule 17.11.2013    source источник
comment
Интегральное продвижение — это именно то, что происходит посредством обычных арифметических преобразований; см. [выражение]/10.   -  person dyp    schedule 17.11.2013


Ответы (3)


Насколько я понимаю, в обоих дополнениях b + a по-прежнему считается добавлением двух подписанных 8-битных переменных. Таким образом, результатом является переполнение, т.е. -128.

Нет, продвижение происходит до оценки +, а не после нее. Сложение происходит, когда оба a и b положительны. Оба числа повышаются до ints для сложения, складываются как два положительных числа, а затем преобразуются в 16-битное короткое. Ни на одном этапе процесса результат не становится отрицательным из-за переполнения, поэтому конечный результат равен 128.

Возможно, в этом есть смысл: поведение a и b совпадает с поведением двух чисел в математике, что делает его более интуитивно понятным для лингвистов.

person Sergey Kalinichenko    schedule 17.11.2013

Это целостное продвижение.

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. Этот процесс называется интегральное продвижение. Далее все операнды преобразуются до типа наибольшего операнда, что называется продвижение типа. [Герберт Шильдт]

Значения переменных b и a будут преобразованы в int, после чего к ним будет применена операция.

person masoud    schedule 17.11.2013

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

  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).

person sqykly    schedule 17.11.2013