Unsigned int (С++) vs uint (С#)
Ниже приведен код С#:
static void Main(string[] args)
{
uint y = 12;
int x = -2;
if (x > y)
Console.WriteLine("x is greater");
else
Console.WriteLine("y is greater");
}
и это код С++:
int _tmain(int argc, _TCHAR* argv[])
{
unsigned int y = 12;
int x = -2;
if(x>y)
printf("x is greater");
else
printf("y is greater");
return 0;
}
Оба дают разные результаты. Я что-то пропустил? Любая идея?
Ответы
Ответ 1
С++ и С# - разные языки. У них есть разные правила для управления продвижением типов в случае сравнений.
В С++ и C их обычно сравнивают, как если бы они были беззнаковыми. Это называется "неподписанным сохранением". Компиляторы С++ и C традиционно используют "неподписанное сохранение", а использование этого указано в стандарте С++ и в K & R.
В С# они оба конвертируются в подписанные longs, а затем сравниваются. Это называется "сохранение ценности". С# указывает сохранение значения.
ANSI C также указывает сохранение значения, но только при работе с шортами и символами. Шорты и символы (подписанные и неподписанные) преобразуются с повышением в ints с сохранением значения, а затем сравниваются. Таким образом, если беззнаковый короткий был сопоставлен с подписанным коротким, результат получился бы как пример С#. Каждый раз, когда выполняется преобразование в больший размер, оно выполняется с сохранением значения, но если две переменные имеют одинаковый размер (а не короткие или символы), а каждый из них без знака, то они сравниваются как беззнаковые величины в ANSI C. Там хорошо обсуждается верхняя и нижняя стороны обоих подходов в часто задаваемом файле comp.lang.c.
Ответ 2
В С++, когда вы сравниваете unsigned int
и a signed int
, signed int
преобразуется в unsigned int
. Преобразование отрицательного signed int
в unsigned int
выполняется путем добавления UINT_MAX + 1
, который больше, чем 12
и, следовательно, результата.
В С#, если вы получаете противоположный результат, это означает, что в С# оба выражения преобразуются в signed int
signed long
(long
или System.Int64
) 1 а затем сравнивается.
В С++ ваш компилятор должен предупредить вас:
предупреждение: сравнение выражений с подписью и без знака
Правило:
Всегда принимайте предупреждения, исходящие от компилятора!
1 Как справедливо указано в комментариях.
Ответ 3
Я не знаю о стандарте С#, но в стандарте С++ usual arithmetic conversions
будет применяться к обоим оперантам реляционных операторов:
[......enum, floating point type involed......]
— Otherwise, the integral promotions (4.5) shall be performed on both operands.
Then the following rules shall be applied to the promoted operands:
— If both operands have the same type, no further conversion is needed.
— Otherwise, if both operands have signed integer types or both have
unsigned integer types, the operand with the type of lesser integer
conversion rank shall be converted to the type of the operand with
greater rank.
— Otherwise, if the operand that has unsigned integer type has rank
greater than or equal to the rank of the type of the other operand, the
operand with signed integer type shall be converted to the type of the
operand with unsigned integer type.
— Otherwise, if the type of the operand with signed integer type can
represent all of the values of the type of the operand with unsigned
integer type, the operand with unsigned integer type shall be converted
to the type of the operand with signed integer type.
— Otherwise, both operands shall be converted to the unsigned integer type
corresponding to the type of the operand with signed integer type.
Таким образом, когда unsigned int
сравнивается с int
, int
будет преобразован в unsigned int
, а -2
станет очень большим числом при преобразовании в unsigned int
.