Подтвердить что ты не робот

Подписанные целые числа без знака для длин/счетчиков

Для представления переменной длины или счетчика лучше использовать подписанные или неподписанные целые числа?

Мне кажется, что С++ STL предпочитает unsigned (std::size_t, как в std::vector:: size(), вместо этого С# BCL предпочитает использовать целые числа со знаком (например, ICollection.Count.

Учитывая, что длина или число - неотрицательные целые числа, моя интуиция выбирает unsigned; но я не понимаю, почему разработчики .NET выбрали знаковые целые числа.

Каков наилучший подход? Каковы плюсы и минусы каждого из них?

4b9b3361

Ответ 1

С++ использует неподписанные значения, потому что им нужен полный диапазон. В 32-битной системе язык должен иметь возможность иметь 4-гигабайтный вектор, а не только 2 ГБ. (ОС может не позволить вам использовать все 4 ГБ, но сам язык не хочет мешать вам)

В .NET целые числа без знака не совместимы с CLS. Вы можете использовать их (на некоторых языках .NET), но это ограничивает мобильность и совместимость. Поэтому для библиотеки базового класса они используют только целые числа со знаком.

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

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

Со знаком целого числа, которое легко обнаружить. С unsigned он обернется и станет UINT_MAX. Это затрудняет обнаружение ошибки, потому что вы ожидали положительного числа, и вы получили положительное число.

Так и есть, это зависит. С++ использует unsigned, потому что ему нужен диапазон..NET использует подписанный, потому что ему нужно работать с языками, которые не имеют unsigned.

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

Ответ 2

Естественно использовать неподписанные типы для подсчетов и размеров, если мы не находимся в каком-то контексте, где они могут быть отрицательными и, тем не менее, иметь смысл. Я предполагаю, что С++ следует этой же логике своего старшего брата C, в котором strlen() возвращает size_t и malloc() принимает size_t.

Проблема в С++ (и C) с целыми числами с подписью и без знака заключается в том, что вы должны знать, как они преобразуются друг к другу, когда вы используете смесь двух видов. Некоторые защитники используют подписанные ints для всего целого, чтобы избежать этой проблемы незнания и невнимательности программистов. Но я думаю, что программисты должны знать, как использовать свои инструменты торговли (языки программирования, компиляторы и т.д.). Рано или поздно они будут немного конвертированы, если не в том, что они написали, а затем в том, что есть у кого-то еще. Это неизбежно.

Итак, знай свои инструменты, выберите то, что имеет смысл в вашей ситуации.

Ответ 3

Здесь есть несколько аспектов:

1) Максимальные значения: обычно максимальное значение подписанного числа равно 1/2 от соответствующего значения без знака. Например, в C максимальное значащее короткое значение составляет 32767, тогда как максимальное беззнаковое короткое значение составляет 65535 (потому что 1/2 диапазона не требуется для чисел -ve). Поэтому, если ваши ожидаемые длины или подсчеты будут значительными, представление без знака имеет больше смысла.

2) Безопасность. Вы можете просмотреть сеть для ошибок переполнения целочисленного числа, но представьте код, например:

if (length <= 100)
{
  // do something with file
}

... тогда, если "length" является знаковым значением, вы рискуете "длиной" быть номером -ve (хотя и злонамеренным намерением, некоторым литым и т.д.), а код, который не выполняется, вы ожидали. Я видел это в предыдущем проекте, где последовательность была увеличена для каждой транзакции, но когда число со знаком, которое мы использовали, достигло значения max signed int (2147483647), оно внезапно стало -ve после следующего приращения, и наш код не смог обработать он.

Только некоторые вещи, о которых нужно подумать, независимо от основных соображений языка/API.

Ответ 4

Если вы не создаете повторно используемую библиотеку (в .NET-терминах, например, проект VB.NET расходует вашу библиотеку классов С#), то выберите то, что работает для вас. Конечно, если вы создаете какую-либо DLL, и вполне возможно, что ваша библиотека может использоваться в проекте с другим языком (опять же, VB.NET приходит на ум), тогда вам нужно помнить о несоответствующих типах (без знака).