Тип по умолчанию: Подпись или Без знака?
При программировании на C-подобном языке должен существовать один целочисленный тип по умолчанию: int или uint/unsigned int? По умолчанию я имею в виду, когда вам не нужны отрицательные числа, но один из них должен быть достаточно большим для данных, которые вы держите. Я могу придумать хорошие аргументы для обоих:
подписано: лучше математически, менее вероятно, странное поведение, если вы попытаетесь опуститься ниже нуля в каком-то граничном случае, о котором вы не думали, вообще избегает нечетных угловых случаев.
unsigned: Предоставляет немного дополнительной гарантии против переполнения, на случай, если ваши предположения о значениях неверны. Служит в качестве документации, что значение, представленное переменной, должно быть никогда отрицательным.
Ответы
Ответ 1
Руководство по стилю Google С++ имеет интересное мнение о целых числах без знака:
(цитата следует:)
В беззнаковые целые числа
Некоторые люди, в том числе некоторые авторы учебников, рекомендуют использовать неподписанные типы для представления чисел, которые никогда не являются отрицательными. Это предусмотрено как самостоятельная документация. Однако в C преимущества такой документации перевешиваются реальными ошибками, которые она может ввести. Рассмотрим:
for (unsigned int i = foo.Length()-1; i >= 0; --i) ...
Этот код никогда не завершится! Иногда gcc замечает эту ошибку и предупреждает вас, но часто этого не будет. Аналогичные ошибки могут возникать при сравнении переменных с подписью и без знака. В принципе, схема продвижения типа C приводит к тому, что неподписанные типы ведут себя иначе, чем можно было бы ожидать.
Итак, запишите, что переменная неотрицательна с помощью утверждений. Не используйте неподписанный тип.
(конечная цитата)
Ответ 2
Конечно, подписан. Если переполнение беспокоит вас, underflow должно беспокоить вас больше, потому что "ниже нуля" случайно легче, чем по int-max.
"unsigned" должен быть сознательным выбором, который заставляет разработчика думать о потенциальных рисках, используемых только там, где вы абсолютно уверены, что вы никогда не сможете пойти отрицательно (даже не случайно) и что вам нужно дополнительное пространство значений.
Ответ 3
Как правило, я использовал unsigned ints для подсчета вещей и подписал ints для измерения вещей.
Если вы обнаруживаете, что вы уменьшаете или вычитаете из неподписанного int, вы должны быть в контексте, когда вы уже ожидаете, что будете проявлять большую осторожность, чтобы не переполнять (например, потому что вы находитесь в некотором низкоуровневом коде, отступающем назад от конца строки, поэтому, конечно, вы сначала обеспечили, чтобы строка была достаточно длинной, чтобы поддержать это). Если вы не находитесь в таком контексте, где абсолютно важно, чтобы вы не опустились ниже нуля, тогда вы должны были использовать знаковое значение.
В моем использовании unsigned ints для значений, которые абсолютно не могут пойти отрицательно (или для этого в миллионной ситуации, когда вы действительно хотите по модулю 2 ^ N арифметики), а не для значений, которые так просто не отрицательны, в текущая реализация, возможно.
Ответ 4
Я имею тенденцию идти со знаком, если я не знаю, что мне нужно без знака, поскольку int
обычно подписывается, и для ввода unsigned int
требуется больше усилий, а uint
может привести к тому, что другой программист немного задумается какие значения могут быть.
Итак, я не вижу никакой пользы, чтобы просто по умолчанию не было без знака, поскольку нормальный int подписан.
Ответ 5
Вы не получаете много "уверенности против переполнения" без знака. Вы, скорее всего, получите другое, но более странное поведение, чем с подписанным, но чуть позже... Лучше получить эти предположения прямо перед рукой?
Ответ 6
Предоставление более специфичного назначения типа (например, unsigned int) передает больше информации об использовании переменной и может помочь компилятору отслеживать любые моменты, когда вы назначаете "неправильное" значение. Например, если вы используете переменную для отслеживания идентификатора базы данных объекта/элемента, там (вероятно) никогда не должно быть времени, когда идентификатор меньше нуля (или одного); в этом случае, вместо того, чтобы утверждать, что состояние, использующее целое число без знака, передает этот оператор другим разработчикам, а также компилятору.
Ответ 7
Я сомневаюсь, что на самом деле есть хороший ответ на язык-агностик. Есть достаточно различий между языками и того, как они обрабатывают смешанные типы, что ни один ответ не имеет смысла для всех (или даже большинства).
В языках, которые я использую чаще всего, я использую подписанный, если у меня нет конкретной причины делать это иначе. Это в основном C и С++. На другом языке я мог бы дать другой ответ.