Целочисленное ли целое число используется как тип данных?


9

Используют ли большинство разработчиков приложений целые числа со знаком в тех местах, где они действительно хотят использовать целые числа без знака? Я делаю это все время, как и мои коллеги. Я не видел много других обширных кодовых баз (кроме Delphi VCL), и примеры в Интернете обычно используют целочисленные значения. Принимая во внимание, что разработчики VCL используют свои собственные типы данных (что было бы наиболее ленивым способом объявления переменных).

Что-то кажется немного ужасным в таком коде

TStuffRec = record
   recordID : Integer;
   thingID : Integer;
   otherThingID : Integer;
end;

когда это может быть написано как

TStuffRec = record
   recordID : Cardinal;
   thingID : Cardinal;
   otherThingID : Cardinal;
end;

Функционально эти записи почти всегда работают одинаково (и, надеюсь, продолжат работать одинаково даже в 64-битной Delphi). Но очень большие числа будут иметь проблемы с конверсией.

Но есть и недостатки использования неподписанных целых. Главным образом проистекает из того, как раздражает смешивать два.

На самом деле вопрос в том, действительно ли об этом думают или включают в лучшие практики? Обычно это зависит только от разработчика?


5
Питер, ты ищешь только специфичные для Delphi ответы?
— Адам Лир

3
@Anna Понимание того, как работают типы данных Delphi, поможет получить превосходный ответ. Я вполне уверен, что программисты на Си могли понять и ответить на этот вопрос.
— Питер Тернер

Ответы:


9

Одна из причин, по которой я не использую целые типы без знака в Delphi, заключается в том, что они могут создавать проблемы при смешивании со знаковыми целыми числами. Вот один, который укусил меня однажды:

for i := 0 to List.Count - 1 do
  //do something here

Я iобъявил как целое число без знака (в конце концов, это индекс в списке, который начинается с 0, он никогда не должен быть отрицательным, верно?), Но когда он List.Countбыл равен 0, он не будет замыкать цикл, как ожидалось, потому что 0 - 1оценивает очень высокое положительное число. К сожалению!

Между потенциальными проблемами безопасности, присущими смешиванию целых чисел со знаком и без знака, и проблемами диапазона (если вам понадобятся положительные числа, большие чем high(signed whatever), вполне вероятно, что вам также понадобятся положительные числа, большие , чем high(unsigned whatever)тоже, поэтому переходите до следующего большего размера вместо того, чтобы переключаться со знака на без знака того же размера, обычно правильное действие,) я действительно не нашел слишком много применений для целых чисел без знака при представлении большинства данных.


2
В некоторой степени связанный, один из основных рисков использования типа данных, который потенциально меньше, чем необходимо (в отличие от просто без знака или со знаком), состоит в том, что если условие выхода больше, чем вы планировали, вы можете фактически получить бесконечный цикл как счетчик переполняется снова и снова. Оглядываясь назад, это звучит глупо, но однажды я написал программу, которая должна была пройти через все возможные значения байтов, и потребовалось около 15 минут, чтобы окончательно убедить себя, что это невозможно сделать со счетчиком байтов.
— Ааронаут

@Aaronaught: не в Дельфи. (По крайней мере, если вы не сделаете что-то глупое, например, отключите встроенную проверку переполнения.) В результате вы получите исключение при переполнении счетчика вместо бесконечного цикла. Это все еще ошибка, но ее намного легче отследить.
— Мейсон Уилер

Если ты так говоришь. Я всегда отключал проверку переполнения в Delphi; после бесконечной бомбардировки ложными срабатываниями от таких вещей, как хэш-коды и контрольные суммы, я просто полностью отказался от этой «функции». Но я полагаю, что вы правы, он бы поймал эту конкретную ошибку.
— Ааронаут

@Aaronaught: Ну, да, вы бы хотели отключить его для таких вещей, как хэш-коды и контрольные суммы, которые специально предназначены для переполнения и переноса. Но для вычислений общего назначения, которые не рассчитаны на переполнение и наматывание, это важная функция безопасности, и отключение - это все равно, что ехать без ремня безопасности.
— Мейсон Уилер

Возможно, вы забыли, но директивы проверки переполнения и компилятора были невероятно ошибочными в старых версиях Delphi. Я хорошо помню, как несколько раз рвал на себе волосы после того, как увидел, что отладчик остановился прямо посередине блока {$ O -} / {$ O +}, чтобы весело сообщить о переполнении. Через некоторое время я больше не мог принимать это и просто отключил это глобально. Опять же, да, это бы уловило эту проблему, но я все еще не думаю, что это стоит того количества ложных срабатываний. Каждому свое, конечно!
— Ааронаут

3

Честно говоря, я склонен использовать целые числа по привычке. Я привык к тому, что они предлагают достаточно большие диапазоны для большинства ситуаций и допускают отрицательные значения (например, -1). Действительно, много раз использование байтов / word / shortint было бы более уместным. Теперь, думая об этом, я могу сосредоточиться на следующих местах:

  • Perspective. Размер карты тайлов ограничен 192x192 тайлами, поэтому я могу использовать байт для адресации тайлов и циклов. Но если размер карты будет увеличен, мне придётся проходить каждое использование и заменять его, например, словом. Когда мне нужно разрешить объекты вне карты, мне нужно будет снова перейти на smallint.

  • Loops. Часто я пишу цикл «от i: = 0 до Count-1», что происходит, если «i» - байт, а Count = 0 - цикл выполняется от 0 до 255. Не то, чтобы я этого хотел.

  • Унифицируйся. Проще запомнить и применить «var i: integer;» чем останавливаться в каждом случае и думать: «Хм .. здесь мы имеем дело с диапазоном 0..120 .. байт .. нет, подождите, нам может понадобиться -1 для неинициализированной .. краткости .. подождите .. что если 128 не достаточно .. Arrgh! " или "Почему в этом месте smallint, а не shortint?"

  • Объединение. Когда мне нужно объединить два или более классов вместе, они могут использовать разные типы данных для своих целей, использование более широких типов позволяет пропустить ненужные преобразования.

  • -1. Даже когда значения находятся в диапазоне 0..n-1, мне часто нужно устанавливать значение «нет значения / неизвестно / неинициализировано / пусто», что по общепринятой практике -1.

Использование целых чисел позволяет пропустить все эти проблемы, забыть о низкоуровневой оптимизации там, где она не нужна, перейти на более высокий уровень и сосредоточиться на более реальных проблемах.

PS Когда я использую другие типы?

  • Счетчики, они никогда не бывают отрицательными и доступны только для чтения за пределами своего класса.
  • Причины производительности / памяти заставляют использовать более короткие типы данных в определенных местах.

1

Рекомендуется использовать тип данных, который соответствует потребностям в используемых данных (ожидаемые данные).

Примеры C #: если бы мне нужно было поддерживать только от 0 до 255, я бы использовал байт.

Если мне нужно было поддержать 1000000 негатива и позитива, тогда int.

Больше, чем 4,2 миллиарда, а затем использовать длинный.

Выбрав правильный тип, программа будет использовать оптимальный объем памяти, а также разные типы используют разные объемы памяти.

Вот ссылка на C # int из MSDN.

int 
 -2,147,483,648 to 2,147,483,647
 Signed 32-bit integer

uint 
 0 to 4,294,967,295
 Unsigned 32-bit integer

long 
 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
 Signed 64-bit integer

ulong 
 0 to 18,446,744,073,709,551,615
 Unsigned 64-bit integer

В C # (или .net в целом) длинные и ulong станут 128 бит на 128-битной машине? Потому что в Delphi Integerтип данных 32-битный на 32-битной машине и 64-битный на 64-битной машине.
— Питер Тернер

1
@Peter Turner: Нет, в C # intэто просто сокращение System.Int32, независимо от того, на какой машине работает код.
— nikie

@nikie, это как- type int System.Int32то так? Может ли это быть легко изменено в будущей версии фреймворка?
— Питер Тернер

@Peter Turner / nikie (sizeof (int) .ToString ()); ==> Возвращает 4 (sizeof (Int64) .ToString ()); ==> Возвращает 8 В моей 64-битной ОС Windows. Как ники, статистика, int действительно просто и Int32.
— Джон Рейнор

1
Одна вещь , чтобы отметить здесь, что не все типы совместимы с спецификацией Common Language . uintявляется одним из таких несовместимых типов, что означает, что его не следует использовать в общедоступном API, чтобы не нарушить возможность использовать этот API на языках .NET, отличных от того, на котором написана библиотека. Именно поэтому .NET Framework API сам использует intгде uintбы делал.
— Адам Лир

1

Целочисленные типы без знака должны использоваться только для представления кардинальных чисел в языках, где они представляют кардинальные числа. Из-за того, что компьютеры, работающие на C, работали, целочисленные типы без знака вели себя как члены алгебраических колец mod-2 ^ n (означая, что переполненные вычисления предсказуемо «обертывают»), а язык указывает, что во многих случаях такие типы требуется вести себя как абстрактные алгебраические кольца, даже если такое поведение будет несовместимо с поведением кардинальных чисел или математических чисел.

Если платформа полностью поддерживает отдельные типы для кардинальных чисел и алгебраических колец, то я бы предложил обрабатывать кардинальные числа с использованием типов кардинальных чисел (и вещей, которые нужно обернуть, используя типы колец). Такие типы могут не только хранить числа, в два раза превышающие размер подписанных типов, но и метод, получающий параметр такого типа, не должен проверять, было ли оно отрицательным.

Однако, учитывая относительное отсутствие типов кардинальных чисел, лучше всего просто использовать целые числа для представления математических и кардинальных чисел.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.