беззнаковое целое (С++) против 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;
}

Оба дают разный результат. Я пропустил что-то основное? Есть идеи?


person Samir Lakhani    schedule 25.11.2011    source источник
comment
возможный дубликат сравнений со знаком/без знака   -  person user541686    schedule 25.11.2011
comment
Общий совет: всегда проверяйте, чтобы оба значения были одного типа для сравнения.   -  person RvdK    schedule 25.11.2011
comment
@Mehrdad: Этот вопрос о том, почему сравнения со знаком и без знака в C++ вызывают предупреждение компилятора, когда используется оператор ‹, ›, ›= или ‹=, но не когда используется оператор ==. Это совершенно другой вопрос, и ответ на него имеет очень мало отношения к ответу на этот.   -  person Keith Irwin    schedule 25.11.2011


Ответы (3)


C++ и C# - разные языки. У них разные правила обработки повышения типа в случае сравнений.

В C++ и C они обычно сравниваются, как если бы они оба были беззнаковыми. Это называется "беззнаковое сохранение". Компиляторы C++ и C традиционно используют «сохранение без знака», и его использование указано в стандарте C++ и в K&R.

В C# они оба преобразуются в длинные числа со знаком, а затем сравниваются. Это называется «сохранение стоимости». C# определяет сохранение значения.

ANSI C также указывает сохранение значений, но только при работе с короткими и символьными символами. Шорты и символы (со знаком и без знака) преобразуются в целые числа с сохранением значения, а затем сравниваются. Таким образом, если беззнаковое короткое значение сравнить с подписанным коротким, результат будет таким же, как в примере C#. Всякий раз, когда выполняется преобразование в больший размер, оно выполняется с сохранением значения, но если две переменные имеют одинаковый размер (а не шорты или символы) и одна из них беззнаковая, то они сравниваются как беззнаковые величины в ANSI C. Достоинства и недостатки обоих подходов подробно обсуждаются в часто задаваемых вопросах comp.lang.c. .

person Keith Irwin    schedule 25.11.2011
comment
Стандарт C++ предоставил правило для обработки этой ситуации, и когда задействованы int и unsigned int, оба операнда будут преобразованы в unsigned int. - person fefe; 25.11.2011
comment
... они обычно сравниваются, как если бы они оба были без знака ... В этом случае каждый компилятор C или C ++ должен преобразовать int в unsigned int. Это предусмотрено формальным стандартом, потому что unsigned может содержать большее значение, чем int. - person Gunther Piez; 25.11.2011
comment
Спасибо за комментарии. Я еще раз проверил, правы ли вы, и, насколько я могу судить, вы правы. Поэтому я изменил ответ. Я также нашел дополнительную информацию о преобразованиях стандарта ANSI C и о том, как они работают (сохранение ценности только при выполнении преобразований с увеличением размера). Поэтому он был обновлен, чтобы отразить и это. - person Keith Irwin; 25.11.2011
comment
Я удалил отрицательный голос. Ответ гораздо точнее знаю - person Gunther Piez; 30.11.2011
comment
Поведение C имеет смысл, если рассматривать беззнаковые целые типы как представляющие элементы абстрактного алгебраического кольца, а не числовые величины. Добавление числа к абстрактному кольцу дает другое кольцо, примерно так же, как добавление числа к указателю дает указатель (хотя, в отличие от указателей, элементы кольца также могут быть добавлены друг к другу). - person supercat; 14.09.2013

В C++ при сравнении unsigned int и signed int signed int преобразуется в unsigned int. Преобразование отрицательного signed int в unsigned int осуществляется добавлением UINT_MAX + 1, которое больше, чем 12, и, следовательно, результат.

В C#, если вы получаете противоположный результат, это означает, что в C# оба выражения преобразуются в signed int signed long (long или System.Int64)1, а затем сравниваются.

В C++ ваш компилятор должен был выдать вам предупреждение:

предупреждение: сравнение между знаковыми и беззнаковыми целочисленными выражениями

Правило:
Всегда серьезно относитесь к предупреждениям, выдаваемым компилятором!

1 Как справедливо заметил svick в комментариях.

person Alok Save    schedule 25.11.2011
comment
В C# выражения преобразуются в длинные со знаком (long или System.Int64). - person svick; 25.11.2011
comment
IIRC, в стандарте C++ нет требований к предупреждающим сообщениям, только сообщения об ошибках. должен => должен? - person dalle; 25.11.2011

Я не знаю о стандарте С#, но в стандарте С++ 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.

person fefe    schedule 25.11.2011