Возможный дубликат:
int делится на unsigned int, вызывая опрокидывание
Привет, я делаю следующее:
struct coord{
int col;
};int main(int argc, char* argv[]) {
coord c;
c.col = 0;
std::vector<coord> v;
for(int i = 0; i < 5; i++){
v.push_back(coord());
}
c.col += -13;cout << " c.col is " << c.col << endl;
cout << " v size is " << v.size() << endl;
c.col /= v.size();cout << c.col << endl;
}
и я получаю следующий вывод:
c.col is -13
v size is 5
858993456
Однако, если я изменю линию деления на c.col /= ((int)v.size());
Я получаю ожидаемый результат:
c.col is -13
v size is 5
-2
Почему это?
Это следствие v.size()
являющийся unsigned
,
Проблема в том, что vector< ... >::size()
возвращается size_t
, который является typedef
для unigned
целочисленный тип. Очевидно, что проблема возникает, когда вы делите целое число со знаком на число без знака.
std :: vector :: size возвращает size_t, который является целым типом без знака, обычно без знака int. Когда вы выполняете арифметическую операцию с ИНТ и без знака int, ИНТ операнд преобразуется в без знака int выполнить операцию. В этом случае -13 преобразуется в без знака int, что некоторое число близко к 4294967295 (FFFFFFFF в шестнадцатеричном). И тогда это делится на 5.
Как уже говорилось, причина в том, что деление со знаком / без знака выполняется путем первого преобразования значения со знаком в без знака.
Таким образом, вы должны предотвратить это, вручную преобразовав значение без знака в тип со знаком.
Есть риск, что v.size()
может быть слишком большим для int
, Но так как дивиденд делает вписаться в int
результат деления довольно скучный, когда делитель больше этого. Таким образом, предполагая, что 2 дополняют, а биты заполнения отсутствуют:
if (v.size() <= INT_MAX) {
c.col /= int(v.size());
} else if (c.col == INT_MIN && v.size() - 1 == INT_MAX) {
c.col = -1;
} else {
c.col = (-1 / 2);
}
В C ++ 03 это определяется реализацией, является ли отрицательное значение, деленное на большее положительное значение, 0 или -1, отсюда и смешной (-1 / 2)
, В C ++ 11 вы можете просто использовать 0.
Чтобы охватить другие представления, помимо дополнения 2, вам нужно по-разному обращаться с особыми случаями.