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

Совет по unsigned int (издание Gangnam Style)

Видео "Стиль Gangnam" (я уверен, что вы его слышали) превысило 2 миллиарда просмотров на youtube. Фактически, Google говорит, что они никогда не ожидали, что видео будет больше 32-битного целого числа... что ссылается на то, что Google использовал int вместо unsigned для своего счетчика просмотров. Мне кажется, им пришлось немного переписать свой код, чтобы разместить более крупные виды.

Проверка руководства по стилю: https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Integer_Types

... они советуют "не использовать целочисленный тип без знака" и дают одну вескую причину: unsigned может быть ошибкой.

Это хорошая причина, но ее можно защитить. Мой вопрос заключается в том, что в практике плохого кодирования использовать unsigned int?

4b9b3361

Ответ 1

Правило Google широко принято в профессиональных кругах. Проблема заключается в том, что неподписанные интегральные типы являются некорректными и имеют неожиданное и неестественное поведение при использовании для числовых значений; Oни не работают хорошо как кардинальный тип. Например, индекс в массив никогда не может быть отрицательным, но имеет смысл писать abs(i1 - i2), чтобы найти расстояние между двумя индексами. Что не будет работать, если i1 и i2 имеют неподписанные типы.

Как правило, это конкретное правило в руководствах стиля Google более или менее соответствует тому, что предполагают разработчики языка. Каждый раз, когда вы видите что-то другое, кроме int, вы можете принять причина для этого. Если это из-за диапазона, оно будет long или long long, или даже int_least64_t. Использование неподписанных типов обычно сигнал о том, что вы имеете дело с битами, а не числовое значение переменная или (по крайней мере, в случае unsigned char), что вы работа с необработанной памятью.

Что касается "самодокументации" использования unsigned: это не задерживается, так как почти всегда есть много значений, которые переменная не может (или не должна) принимать, в том числе много положительных. С++ не имеет типов поддиапазонов, а способ unsigned определяется средствами что он не может быть использован как один.

Ответ 2

Это правило чрезвычайно вводит в заблуждение. Слепо использование int вместо unsigned int ничего не решит. Это просто переносит проблемы где-то в другом месте. Вы абсолютно должны знать о переполнении целого числа при выполнении арифметики по целым целям фиксированной точности. Если ваш код написан таким образом, что он не обрабатывает целочисленное переполнение грамотно для некоторых заданных входов, ваш код будет нарушен независимо от того, используете ли вы signed или unsigned int s. С unsigned int вы также должны знать о нижнем потоке с целыми числами, а также с double и float вы должны знать о многих дополнительных проблемах с арифметикой с плавающей запятой.

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

Ответ 3

Используйте правильный тип для операций, которые вы будете выполнять. float не имеет смысла для счетчика. Также не существует signed int. Обычными операциями на счетчике являются print и +=1.

Даже если у вас были необычные операции, такие как печать разницы в просмотрах, у вас не было бы проблем. Конечно, в других ответах упоминается некорректный abs(i2-i1), но неразумно ожидать, что программисты будут использовать правильный max(i2,i1) - min(i2,i1). У этого есть проблемы с диапазоном для signed int. Здесь нет единого решения; программисты должны понимать свойства типов, с которыми они работают.

Ответ 4

Google заявляет, что: "Некоторые люди, в том числе некоторые авторы учебников, рекомендуют использовать типы unsigned для представления чисел, которые никогда не являются отрицательными. Это предназначено как форма самодокументации".

Я лично использую unsigned int как параметры индекса.

int foo(unsigned int index, int* myArray){
    return myArray[index];
}

Google предлагает: "Документ о том, что переменная неотрицательна с использованием утверждений. Не используйте неподписанный тип".

int foo(int index, int* myArray){
    assert(index >= 0);
    return myArray[index];
}

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

Pro для меня: мой код может поддерживать больший размер myArray.

Я думаю, что фактический решающий фактор сводится к тому, насколько чистым является ваш код? Если вы очистите все предупреждения, будет ясно, когда компилятор предупреждает вас, когда вы пытаетесь присвоить подписанную переменную переменной unsigned. Если в вашем коде уже есть куча предупреждений, предупреждение компилятора будет потеряно для вас.

Последнее замечание здесь: Google говорит: "Иногда gcc замечает эту ошибку и предупреждает вас, но часто этого не будет". Я не видел, чтобы это было в Visual Studio, проверки на отрицательные числа и назначения из подписанного без знака всегда предупреждаются. Но если вы используете gcc, у вас может быть забота.

Ответ 5

У вас есть конкретный вопрос:

"Неплохо ли использовать неподписанную?" к которому единственным правильным ответом может быть нет. Это не плохая практика.

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

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

CERT IIRC рекомендует индексировать индексы без знака, потому что, если вы переполняете, по крайней мере, вы по-прежнему будете в своем собственном буфере, там есть какая-то внутренняя безопасность.

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

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