Без подписки
Рассмотрим следующее:
#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/