Без подписки

Рассмотрим следующее:

#include <iostream>

int main() {

    unsigned int x = 3;
    unsigned int y = 5;

    std::cout << "a: " << x - y        << std::endl;

    std::cout << "b: " << ((int)x) - y << std::endl;

    std::cout << "c: " << x - ((int)y) << std::endl;

    std::cout << "d: " << ((int)x) - ((int)y) << std::endl;

}

$ g++ -Wconversion -Wall uint_stackoverflow.cc -o uint_stackoverflow && ./uint_stackoverflow
a: 4294967294
b: 4294967294
c: 4294967294
d: -2

Я понимаю, почему "а" не дает ожидаемого результата. Но почему "b" и "c" терпят неудачу. Для "b" я подумал, что после нажатия "x" на "int" результат будет снова "int".

Не могли бы вы просветить меня?

edit: Не следует ли предупреждать компилятор? g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5

Спасибо,

Кто-нибудь

Ответы

Ответ 1

В арифметических операциях, если какой-либо из операндов unsigned, другой операнд преобразуется в unsigned (если его signed), и результат операций будет также unsigned.

Кроме того, отбрасывание unsigned в signed, а затем выполнение операции не изменяет представление битов операнда. В архитектуре с двумя дополнениями (почти каждая современная архитектура) (int)x имеет такое же представление битов, что и x, при вычислении их значения в десятичной системе изменяется только их интерпретация. Но важным моментом является то, что арифметическая операция выполняется над представлениями битов ( не по их значениям в десятичной системе). И так как кастинг не меняет представление битов, битное представление результата также НЕ изменится.

С++ 03 Стандарт говорит в §5/9:

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

[...]

В противном случае , если один из операндов без знака, другое должно быть преобразовано to unsigned.

Ответ 2

Цитата стандартного, как обычно....

Для С++ 98, § [expr]/9:

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

  • Если любой из операндов имеет тип long double, другой должен быть преобразован до long double.
  • В противном случае, если любой операнд double, другой должен быть преобразован до double.
  • В противном случае, если любой операнд float, другой должен быть преобразован до float.
  • В противном случае интегральные акции (4.5) должны выполняться на обоих операнды. 54)
  • Затем, если любой операнд unsigned long, другой должен быть преобразован в unsigned long.
  • В противном случае, если один операнд является long int, а другой unsigned int, то если a long int может представлять все значения a unsigned int, unsigned int преобразуется в long int; в противном случае оба операнда преобразуется в unsigned long int.
  • В противном случае, если любой операнд long, другой должен быть преобразован до long.
  • В противном случае, если любой операнд unsigned, другой должен быть преобразован в unsigned.

[Примечание: в противном случае единственным оставшимся дело в том, что оба операнда int]

В принципе, его можно суммировать как

  • long double > double > float > unsigned long > long > unsigned > int
  • (Типы меньше int будут преобразованы в int)

Текст изменен для С++ 0x (§ [expr]/10) после 5-го элемента, но эффект на код OP тот же: int будет преобразован в unsigned.

Ответ 3

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

Если вы не уверены в типах, но знаете тип результата, который хотите, тогда вы должны использовать как x, так и y, как в d.

Это действительно хорошее объяснение преобразования типов:

http://www.learncpp.com/cpp-tutorial/44-type-conversion-and-casting/