Які випадки, коли 'uint' та 'short' типи даних краще підходять, ніж стандартний int (32)?


24

Я розумію різницю у ємності та цінності, яку вони можуть представляти, але здається, що люди завжди користуються Int32незалежно від того, чи це підходить. Здається, ніхто ніколи не використовує непідписану версію ( uint), хоча багато часу вона підходить краще, оскільки вона описує значення, яке не може бути негативним (можливо, для представлення ідентифікатора запису бази даних). Також, здається, ніхто ніколи не використовує short/Int16незалежно від необхідної ємності значення.

Об'єктивно, існують випадки , коли краще використовувати uintабо short/Int16і якщо так, то вони?


13
Популярність не завжди є життєздатною метрикою для оцінки рішень щодо проектування програмного забезпечення. Тільки тому, що практика є популярною, не означає, що вона є відповідною практикою для вашої конкретної програми, або що це навіть хороша практика.
Роберт Харві


1
Я вважаю, що коротка відповідь полягає в тому, що програмісти звикли до підписаної семантики і схильні вважати їх, навіть коли мають справу з непідписаними типами (і, таким чином, безпідписаною семантикою). Більшість людей припускають, що програміст лінивий чи неосвічений, проте, про який йде мова, насправді може бути дуже освіченим і дуже обережним і хоче уникати тонких підводних каменів. Якщо вам подобається, подивіться на soundsoftware.ac.uk/c-pitfall-unsigned та anteru.net/2010/05/17/736 .
Теодорос Чатзіґянакікіс

У безпідписаному числі знак більше nullніж позитивний чи негативний. Якщо ви думаєте про це як про щось, що ніколи не може бути негативним або завжди позитивним, ви будете здивовані (і часто злі) результатам, оскільки це насправді не працює таким чином, особливо якщо порівнювати з або відняти / від підписаних значень.
Адам Д. Руппе

1
На моєму досвіді багато програмістів, які коли-небудь програмували мовою С, як правило, піклуються про байти ГБ пам’яті та місця для зберігання.
user1451111

Відповіді:


25

Я підозрюю, що ви маєте на увазі перспективу, забарвлену власним досвідом, коли ви не працювали над людьми, які правильно використовують цілісні типи. Це цілком може бути звичайним явищем, але, як мій досвід, люди зазвичай також користуються ними правильно.

Перевага - це простір пам'яті та час процесора, можливо, IO-простір, а також залежно від того, чи типи передаються коли-небудь по дроту або на диск. Непідписані типи дають вам перевірку компілятора, щоб переконатися, що ви не будете робити певних операцій, які неможливі, плюс розширити доступний діапазон, зберігаючи менший розмір для підвищення продуктивності, де це можливо.

Правильне використання , як і слід було очікувати - в будь-який час ви знаєте напевно ви можете використовувати їх на постійній основі (не обмежують без впевненості або ви будете шкодувати про це пізніше).

  • Якщо ви намагаєтесь зобразити щось, що ніколи не може бути негативно ( public uint NumberOfPeople), використовуйте неподписаний тип.
  • Якщо ви намагаєтесь зобразити щось, що ніколи не може бути більшим за 255 ( public byte DamagedToothCount), використовуйте байт.
  • Якщо ви намагаєтесь представити щось, що може бути розумно більшим за 255, але ніколи не має великої кількості тисяч , використовуйте короткий ( public short JimmyHoffasBankBalance).
  • Якщо ви намагаєтесь зобразити щось, що може становити багато сотень тисяч, мільйони навіть, але навряд чи колись досягне декількох мільярдів, використовуйте int ( public int HoursSinceUnixEpoch).
  • Якщо ви точно знаєте, це число може мати безмежно велике значення або ви думаєте, що воно може мати кілька мільярдів, але ви не впевнені, скільки мільярдів, довгий - найкраща ставка. Якщо довгий не досить великий, у вас є цікава проблема, і вам потрібно почати дивитися довільну число точності ( public long MyReallyGreatAppsUserCountThisIsNotWishfulThinkingAtAll).

Це міркування можна використовувати в усьому світі для вибору між підписаними, непідписаними та різними розмірами типів та ін., Лише подумайте про логічні істини даних, які ви представляєте насправді.


11
+1, хоча я маю дати зрозуміти, що "номери телефонів" - це не цифри, а рядки цифр і необов'язково форматування. Ви, здається, це знаєте, але ми не хочемо наводити поганий приклад, тепер чи не так? Крім того, довільно обмежувати діапазон деякого значення - це недалекоглядний антипатерн - intскрізь, якщо ви не знаєте про те, що проблемний домен насправді обмежує значення - жоден банк не бажає жорстко обмежувати рахунки до 33-кілограмового (і думати про забаву коли це переповнює…!).
амон

3
Нова життєва мета: значне надмірне надходження, яке підриває інтегральний тип мого банківського рахунку.
recursion.ninja

11
Є вагомі причини не використовувати неподписані типи в певних місцях, наприклад, коли арифметика змішується між підписаними та неподписаними. Дивіться, які найкращі практики щодо неподписаних літер? .

19
Я не згоден з міркуваннями тут. Непідписані типи часто є помилкою, оскільки віднімання та порівняння є несподіваним, якщо ви звикли до ints (вони працюють послідовно, але це не завжди "позитивно"). Я б їх уникав, якщо у вас немає конкретної причини використовувати їх. Крім того, чому розмір має значення для байта проти короткого проти int? Ви часто навіть не заощаджуєте простір, оскільки структури додадуть ці члени або масиви до певного вирівнювання. Я б використовував байт лише в тому випадку, якщо розмір дійсно важливий (навряд чи особливо для коду C #, який я бачив) або якщо ви конкретно хочете щось розгорнути на 255.
Адам Д. Руппе

4
"користь - це простір пам'яті та час процесора" ... Я не бачу жодного випадку, коли крихітні типи фактично заощаджували б час процесора. Операції з цілим числом ніколи не стають швидшими, ніж на типи розмірів машини , тобто, що стосується процесора, ви також можете використовувати long. Збереження пам'яті може, звичайно, побічно економити час, покращуючи ефективність кеш-ліній тощо, але OTOH проблеми з вирівнюванням малих типів можуть побічно коштувати часу.
близько

16

Звичайно, є випадки, коли краще використовувати uintабо shortабо Int16. Коли ви знаєте, що діапазон ваших даних буде відповідати обмеженням цього типу змінної, тоді використовувати цей тип нормально.

У середовищах з обмеженою пам'яттю або при роботі з великою кількістю об'єктів може бути сенс використовувати найменшу змінну розміру. Наприклад, існує значна різниця у розмірах для масиву мільйонів елементів ints проти shorts.

Часто це не відбувається в фактичному коді з однієї або декількох з наступних причин:

  • Обмеження даних раніше не були відомі
  • Існував шанс, що обмеження даних не були суцільними або, як відомо, вони могли бути змінені
  • Була надія на повторне використання функції з більш широким діапазоном даних
  • Розробник не витрачав часу на роздуми над обмеженнями
  • Економія пам’яті була незначною для обґрунтування використання меншого типу змінної

Існує набагато більше можливих причин, але вони зводяться до цього: час, який приймається для прийняття рішення та використання іншого типу змінної, не давав достатньої користі для виправдання цього.


8

У C в контекстах, що не включають ціле просування , непідписані значення визначали, як вони поводяться як члени "обгорткового" абстрактного алгебраїчного кільця (тому для будь-яких X і Y XY дасть унікальне значення, яке при додаванні до Y дасть X ), тоді як підписані цілочисельні типи визначалися як такі, що поводяться як цілі числа, коли обчислення залишалися в певному діапазоні, і дозволяли їм робити що-небудь взагалі, коли обчислення виходили за рамки цього. Числова семантика в C #, однак, абсолютно інша. Коли в межах перевіреного числового контексту, як підписані, так і непідписані типи поводяться як цілі числа за умови, що обчислення залишаються в діапазоні, і кидають, OverflowExceptionколи їх немає; в неперевіреному контексті вони обидва поводяться як алгебраїчні кільця.

Єдиний раз, коли взагалі варто використовувати будь-який тип даних, менший, ніж Int32це коли потрібно упакувати чи розпакувати речі для компактного зберігання чи транспортування. Якщо вам потрібно зберегти півмільярда позитивних цифр, і всі вони будуть в діапазоні від 0 до 100, використовуючи один байт кожен, а не чотири, заощадите 1,5 гігабайта пам’яті. Це велика економія. Однак, якщо фрагмент коду повинен зберігати загалом пару сотень значень, то, зробивши кожен з них один байт, а не чотири, заощадить близько 600 байт. Напевно, не варто турбуватися.

Що стосується непідписаних типів, єдиний раз, коли вони дійсно корисні, це при здійсненні обміну інформацією або підрозділенні чисел на частини. Якщо, наприклад, потрібно робити математику на 96-бітових цілих числах, можливо, буде набагато простіше виконувати обчислення на групах з трьох непідписаних 32-бітових цілих чисел, ніж на групах підписаних цілих чисел. В іншому випадку, існує не так багато ситуацій, коли діапазон підписаного 32- або 64-бітного значення був би недостатнім, але буде достатньо одного розміру неподписаного значення.


4

Зазвичай погана ідея використовувати неподписані типи, оскільки вони переповнюються неприємними способами. x = 5-6раптом є тимчасовою бомбою у вашому коді. Тим часом переваги непідписаних типів зводяться до ще однієї додаткової долі точності, і якщо цей біт вартий того для вас, вам майже напевно слід скористатися більш великим типом.

Бувають випадки використання, коли менший тип може мати сенс, але якщо ви не турбуєтесь про використання пам'яті або потрібно запакувати дані для ефективності передачі чи кешування або ж кілька інших проблем, зазвичай не буває користі використовувати менший тип . Більше того, у багатьох архітектурах фактично повільніше використовувати ці типи, щоб вони насправді могли покласти невеликі витрати.


3
У C підписане переповнення навіть гірше, ніж неподписане переповнення (тому що це невизначена поведінка, тоді як непідписаний задається для перекидання, як одометр). OTOH, підписаний over / underflow набагато рідше зустрічається на практиці, ніж підпис без підпису.
Кевін

Правда, але підписаний перелив зазвичай більш очевидний і передбачуваний.
Джек Едлі

Я взагалі згоден, але ви повинні знати, що , наприклад, сучасні компілятори можуть оптимізувати i+1>iв 1разі iпідписання, поряд з цілим рядом іншого неприємного поведінки. Ненаписане переповнення може спричинити помилку у кутовому корпусі. Переповнений підпис може зробити всю вашу програму безглуздою .
Кевін

@JackAidley Я впевнений, що те, що ви говорите, не має сенсу, оскільки 5-6 дає той самий бітовий зразок, незалежно від того, підписаний він чи ні.
Інго

@Ingo: як часто ви переглядаєте бітові візерунки? Важливо те, що значення бітового шаблону, а не бітів увімкнено чи вимкнено.
Джек Едлі

2

Часто забувається і, можливо, дотичне до вашого питання, коли мова йде конкретно про типи .NET, це відповідність CLS . Не всі типи доступні для всіх мов, побудованих на .NET Framework.

Якщо ви пишете код, який буде використовуватися іншими мовами, ніж C #, і хочете, щоб цей код гарантував взаємодію з якомога більшою кількістю мов .NET, тоді ви повинні обмежити використання свого типу лише тими, які відповідають стандартам CLS.

Наприклад, ранні версії VB.NET (7.0 і 7.1) не підтримували непідписані цілі числа ( UInteger):

http://msdn.microsoft.com/en-us/library/aa903459(v=vs.71).aspx

Цілі без підпису не відповідають стандартам CLS, тому їх слід використовувати обережно, якщо ви не впевнені, ким буде споживач бібліотеки класів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.