Недавно я подумал об использовании целых чисел без знака в C # (и я думаю, что аналогичный аргумент можно сказать о других "языках высокого уровня")
Когда я нуждаюсь в целом числе, я обычно не сталкиваюсь с дилеммой размера целого числа, примером может служить свойство age класса Person (но вопрос не ограничивается свойствами). Имея это в виду, насколько я вижу, есть только одно преимущество использования целого без знака («uint») над целым числом со знаком («int») - читаемость. Если я хочу выразить идею о том, что возраст может быть только положительным, я могу достичь этого, установив тип возраста в uint.
С другой стороны, вычисления на целых числах без знака могут привести к ошибкам всех видов, что затрудняет выполнение таких операций, как вычитание двух возрастов. (Я читал, что это одна из причин, почему Java пропустил целые числа без знака)
В случае C # я также могу подумать, что защитное предложение для установщика было бы решением, которое дает лучшее из двух миров, но это не будет применимо, когда, например, для некоторого метода будет задан возраст. Обходной путь должен был бы определить класс с именем Age, и свойство age было бы единственным, но этот шаблон заставил бы меня создавать много классов и был бы источником путаницы (другие разработчики не знали бы, когда объект является просто оболочкой). и когда это что-то более изощренное).
Каковы общие рекомендации по этому вопросу? Как я должен иметь дело с этим типом сценария?
источник
Ответы:
Разработчики .NET Framework выбрали 32-разрядное целое число со знаком в качестве «общего числа» по нескольким причинам:
Причиной использования неподписанных целых не является удобочитаемость; у него есть возможность получить математику, которую предоставляет только неподписанный тип int.
Охранные положения, проверка и предварительные условия контракта являются вполне приемлемыми способами обеспечения допустимых числовых диапазонов. Редко когда реальный числовой диапазон соответствует в точности номеру от 0 до 2 32 -1 (или любой другой родной числовой диапазон того типа, который вы выбрали), поэтому использование
uint
ограничения интерфейса вашего контракта на положительные числа является своего рода не в этом дело.источник
for (uint j=some_size-1; j >= 0; --j)
- whoops ( не уверен, если это проблема в C #)! Я обнаружил эту проблему в коде, который до этого пытался максимально использовать unsigned int на стороне C - и в итоге мы изменили его наint
более благоприятный , и наша жизнь стала намного проще с меньшим количеством предупреждений компилятора.int
большую часть времени, потому что это установленное соглашение, и это то, что большинство людей ожидают увидеть в повседневном использовании. Используйте,uint
когда вам требуются специальные возможности auint
». Помните, что разработчики Framework решили тщательно следовать этому соглашению, поэтому вы даже не можете использовать егоuint
во многих контекстах Framework (он не совместим с типами).Как правило, вы всегда должны использовать наиболее конкретный тип данных для ваших данных.
Например, если вы используете Entity Framework для извлечения данных из базы данных, EF автоматически использует тип данных, ближайший к тому, который используется в базе данных.
Есть две проблемы с этим в C #.
Во-первых, большинство разработчиков на C # используют только
int
для представления целых чисел (если нет причин использоватьlong
). Это означает, что другие разработчики не будут думать о проверке типа данных, поэтому они получат ошибки переполнения, упомянутые выше. Во - вторых, и более важным вопросом, является / в том , что .NET в исходные арифметические операторы поддерживаются толькоint
,uint
,long
,ulong
,float
, двойной, иdecimal
*. Это все еще актуально сегодня (см. Раздел 7.8.4 в спецификации языка C # 5.0 ). Вы можете проверить это самостоятельно, используя следующий код:Результат нашего
byte
-byte
этоint
(System.Int32
).Эти два вопроса привели к распространенной практике «единственное использование целых чисел».
Поэтому, чтобы ответить на ваш вопрос, в C # обычно стоит придерживаться следующих
int
правил:byte
и aint
или aint
и along
является критической, или арифметические различия без знака уже упоминались).Если вам нужно сделать математику с данными, придерживайтесь общих типов.
Помните, что вы можете кастовать из одного типа в другой. Это может быть менее эффективно с точки зрения процессора, поэтому вам, вероятно, лучше использовать один из 7 распространенных типов, но это вариант, если необходимо.
Enumerations (
enum
) - одно из моих личных исключений из приведенных выше рекомендаций. Если у меня есть только несколько вариантов, я укажу перечисление в байтах или коротких. Если мне понадобится последний бит во помеченном перечислении, я укажу тип, который должен быть,uint
чтобы я мог использовать hex для установки значения для флага.Если вы используете свойство с кодом, ограничивающим значение, обязательно объясните в итоговом теге, какие существуют ограничения и почему.
Псевдонимы * C # используются вместо имен .NET, например,
System.Int32
так как это вопрос C #.Примечание: был блог или статья от разработчиков .NET (которую я не могу найти), в которой указывалось на ограниченное количество арифметических функций и некоторые причины, по которым они не беспокоились об этом. Насколько я помню, они указали, что не планируют добавлять поддержку для других типов данных.
Примечание. Java не поддерживает типы данных без знака и ранее не поддерживала 8- или 16-битные целые числа. Поскольку многие разработчики на C # пришли из Java-опыта или должны были работать на обоих языках, ограничения одного языка иногда искусственно накладывались на другой.
источник
В основном вам необходимо знать две вещи: данные, которые вы представляете, и любые промежуточные этапы ваших расчетов.
Конечно, имеет смысл иметь возраст
unsigned int
, потому что мы обычно не учитываем отрицательный возраст. Но тогда вы упоминаете вычитание одного возраста из другого. Если мы просто слепо вычтем одно целое число из другого, то определенно можно получить отрицательное число, даже если мы ранее согласились с тем, что отрицательный возраст не имеет смысла. Так что в этом случае вы хотите, чтобы ваш расчет был выполнен со знаком целого числа.Относительно того, являются ли неподписанные значения плохими или нет, я бы сказал, что обобщение того, что неподписанные значения являются плохими, является огромным обобщением. Как вы упоминали, в Java нет значений без знака, и это постоянно раздражает меня. A
byte
может иметь значение от 0 до 255 или 0x00-0xFF. Но если вы хотите создать экземпляр байта больше 127 (0x7F), вы должны либо записать его как отрицательное число, либо привести целое число к байту. Вы получите код, который выглядит следующим образом:Вышесказанное раздражает меня до бесконечности. Мне не разрешают иметь значение байта 197, хотя это вполне допустимое значение для большинства здравомыслящих людей, имеющих дело с байтами. Я могу привести целое число или найти отрицательное значение (в данном случае 197 == -59). Также учтите это:
Итак, как вы можете видеть, добавление двух байтов с допустимыми значениями и получение байта с действительным значением приводит к изменению знака. Не только это, но не сразу очевидно, что 70 + 80 == -106. Технически это переполнение, но, по моему мнению (как человеческое существо), байт не должен переполняться для значений ниже 0xFF. Когда я делаю битовую арифметику на бумаге, я не считаю 8-й бит знаковым битом.
Я работаю с большим количеством целых чисел на битовом уровне, и наличие всего подписываемого обычно делает все менее интуитивно понятным и более сложным, поскольку вы должны помнить, что смещение вправо отрицательного числа дает вам новые числа
1
в вашем номере. В то время как смещение вправо без знака целое число никогда не делает этого. Например:Это просто добавляет дополнительные шаги, которые, я считаю, не нужны.
Хотя я использовал
byte
выше, то же самое относится к 32-разрядным и 64-разрядным целым числам. Отсутствиеunsigned
вредно для меня, и это шокирует меня тем, что существуют языки высокого уровня, такие как Java, которые вообще их не допускают. Но для большинства людей это не проблема, потому что многие программисты не имеют дело с арифметикой на уровне битов.В конце концов, полезно использовать целые числа без знака, если вы думаете о них как о битах, и полезно использовать целые числа со знаком, когда вы думаете о них как о числах.
источник