unsigned int (c++) срещу uint (c#)

Следва кодът на c#:

   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");
    }

и това е C++ код:

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 компилаторите традиционно използват "unsigned preserving" и използването на това е посочено в стандарта C++ и в K&R.

В C# и двете се преобразуват в дълги със знак и след това се сравняват. Това се нарича "запазване на стойността". C# указва запазване на стойността.

ANSI C също уточнява запазване на стойността, но само когато се работи с shorts и chars. Shorts и chars (подписани и неподписани) се преобразуват в int по начин, запазващ стойността, и след това се сравняват. Така че, ако unsigned short се сравни с signed short, резултатът ще излезе като примера на C#. Всеки път, когато се извършва преобразуване в по-голям размер, това се извършва по начин, запазващ стойността, но ако двете променливи са с еднакъв размер (а не shorts или chars) и някоя от тях е без знак, тогава те се сравняват като количества без знак в 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

Не знам за стандарта на C#, но в стандарта C++ 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