Тип по умолчанию: Подпись или Без знака?

При программировании на 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 и С++. На другом языке я мог бы дать другой ответ.