Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Даже во многих современных программах на C++ часто вижу int/short/long там, где по смыслу должно быть беззнаковое целое. А в ранних программах знаковые целые вообще использовались везде, где было технически возможно. Даже в классической книге Кернигана/Ритчи множество примеров, где счетчики, индексы и прочие имеют знаковый тип. В виндовых SDK, где знаковость в основном используется адекватно, все равно регулярно встречаются знаковые параметры размеров, количеств и прочего, где не используются отрицательные значения для особых случаев.
ЕМ>Откуда такое пристрастие, кроме как от лени? Вроде как сколько-нибудь массовых процессоров, где беззнаковые целые поддерживались бы ограниченно, не существует. Есть в этом хоть какое-то рациональное зерно?
Никто не считает яблоки и не задаёт порядковый номера домов в "беззнаковых целых числах", все думают о них как о "целых". Поэтому и слово unsigned (или буква u в начале) превращает мысленно проговариваемое "целое число" в некое "беззнаковое целое число". Для меня это веская причина, т.к. код читают люди, а отвлекать их от чтения — плохая идея. Не сомневаюсь, что и Кернихан с Ричи руководствовались этим же соображением.
С другой стороны, когда авторы хотят подчеркнуть, что знака не должно быть, это тоже веская причина использовать unsigned. И веская тоже потому, что код читают люди. Но при этом, я считаю, возникает дополнительная ответственность. Надо убедиться, что моделируемое число в предметной области никогда не должно быть отрицательным (чего часто не делают). Что при расчётах промежуточные результаты не уйдут за ноль. Что для передачи ошибки предусмотрен другой канал. А если всего этого не делают, то уж лучше использовать знаковое. Которое является просто максимально общим случаем. Избыточное обобщение не ошибка, а избыточное сужение — да.
К счастью, в большинстве случаев это неважно. Работать с коллекциями лучше в функциональном стиле, а размер вообще не считать числом.
Здравствуйте, CRT, Вы писали:
CRT>Здравствуйте, T4r4sB, Вы писали:
TB>>Ты на беззнаках даже тупо от ЭН до нуля проитерироваться не можешь без дополнительного бубна.
CRT>просто и интуитивно понятно CRT>i != (unsigned)-1; --i) {
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
CRT>>просто и интуитивно понятно CRT>>i != (unsigned)-1; --i) {
TB>
и что не так?
тебе нужен диапазон значений в цикле [n-1;0]
значит при -1 надо выходить, что и отражено в условии.
так что всё очень явно и понятно.
или тебе (unsigned)-1 кажется непонятным? Ну это только если ты не понимаешь как числа в памяти представлены и что процессор не различает знаковые/беззнаковые при сложении, вычитании, сравнении
Здравствуйте, CRT, Вы писали:
CRT>Здравствуйте, T4r4sB, Вы писали:
CRT>>>просто и интуитивно понятно CRT>>>i != (unsigned)-1; --i) {
TB>>
CRT>и что не так? CRT>тебе нужен диапазон значений в цикле [n-1;0] CRT>значит при -1 надо выходить, что и отражено в условии. CRT>так что всё очень явно и понятно. CRT>или тебе (unsigned)-1 кажется непонятным? Ну это только если ты не понимаешь как числа в памяти представлены и что процессор не различает знаковые/беззнаковые при сложении, вычитании, сравнении
Не знаю, что у Тараса, а для меня — у тебя тут аж два момента на взоржать.
Первый — твоё "интуитивно" понятно. Это как раз не интуитивно и требует адаптации, хоть и относительно лёгкой.
И тут есть ещё одна проблема. Если ты идёшь по циклу строго с шагом 1 — такая идиома действительно понятна. Но если тебе нужен больший шаг, то она уже не работает — тебе или надо, например, одновременно сравнивать с -1, -2, -3, какой там у тебя максимальный шаг, или (хотя бы) переходить со сравнения на равенство — на сравнение на больше-меньше.
Если у тебя есть запас значений, то сравнение i>=N может быть безопасным. Если нет, то тебе надо следить непосредственно за фактом перехода через 0, а не за самими значениями.
А второй — что это всё уже неоднократно проговаривалось в данной дискуссии, а ты влез в остывший тред и кэпствуешь с самого начала.
Здравствуйте, CRT, Вы писали:
CRT>или тебе (unsigned)-1 кажется непонятным?
Да, это как-то контр-интуитивно, не?
CRT>Ну это только если ты не понимаешь как числа в памяти представлены и что процессор не различает знаковые/беззнаковые при сложении, вычитании, сравнении
Я всё это прекрасно знаю, но необходимость так уродовать код говорит о том, что был выбран неверный тип.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, netch80, Вы писали:
N>И тут есть ещё одна проблема. Если ты идёшь по циклу строго с шагом 1 — такая идиома действительно понятна. Но если тебе нужен больший шаг, то она уже не работает — тебе или надо, например, одновременно сравнивать с -1, -2, -3, какой там у тебя максимальный шаг, или (хотя бы) переходить со сравнения на равенство — на сравнение на больше-меньше. N>Если у тебя есть запас значений, то сравнение i>=N может быть безопасным. Если нет, то тебе надо следить непосредственно за фактом перехода через 0, а не за самими значениями.
Решается банальным сравнением с N
for(unsigned i=N-1;i<N;i-=M)
Но вообще согласен, тема не стоит выеденного яйца кроме редких случаев, когда нужны все 32 бита.
N>Не знаю, что у Тараса, а для меня — у тебя тут аж два момента на взоржать.
N>Первый — твоё "интуитивно" понятно. Это как раз не интуитивно и требует адаптации, хоть и относительно лёгкой.
N>И тут есть ещё одна проблема. Если ты идёшь по циклу строго с шагом 1 — такая идиома действительно понятна.
То "взоржал", то "такая идиома действительно понятна"
N>Но если тебе нужен больший шаг, то она уже не работает
Она и не рассчитана на больший шаг. Такой задачи и не ставилось. Если кто-то использует алгоритм для того для чего он не предназначен, то проблема не в алгоритме.
Здравствуйте, CRT, Вы писали:
CRT>Она и не рассчитана на больший шаг. Такой задачи и не ставилось. Если кто-то использует алгоритм для того для чего он не предназначен, то проблема не в алгоритме.
Не слишком ли много всяких "но" (причём уникальных для каждого частного случая) для такой простой фигни? Напоминаю, что для знаковых чисел цикл пишется тупо без фигни, что намекает, что знаковые числа явно более подходят для подавляющего большинства задач.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, CRT, Вы писали:
CRT>То "взоржал", то "такая идиома действительно понятна"
Потому что между "понятна" и "интуитивно понятна" огромаднейшая пропасть.
N>>Но если тебе нужен больший шаг, то она уже не работает CRT>Она и не рассчитана на больший шаг. Такой задачи и не ставилось. Если кто-то использует алгоритм для того для чего он не предназначен, то проблема не в алгоритме.
Я понял, против остальных тезисов возражений нет?
The God is real, unless declared integer.
Re: UPD: это, оказывается, некропост. Кто-то зачем-то поднял
Здравствуйте, Alekzander, Вы писали:
A>Никто не считает яблоки и не задаёт порядковый номера домов в "беззнаковых целых числах", все думают о них как о "целых". Поэтому и слово unsigned (или буква u в начале) превращает мысленно проговариваемое "целое число" в некое "беззнаковое целое число".
Тут есть ещё одно. Беззнаковое целое в C|C++ — это не условный integer range(0,2**N-1), где N — количество бит (в наших реалиях обычно 32). Это integer modulo 2**N.
А название этого не отражает. Приходится постоянно держать в голове факт маппинга между терминами, и учить тех, кто этого не понимает.
A> Для меня это веская причина, т.к. код читают люди, а отвлекать их от чтения — плохая идея. Не сомневаюсь, что и Кернихан с Ричи руководствовались этим же соображением.
Во времена, когда они этим занимались, всё ещё было слишком примитивно и туманно. Нет, тут комитет постарался. Стандарт 85-го года начал стандартизовать язык, это хорошо, но они одновременно вогнали в него 100500 диверсий на будущее.
A>С другой стороны, когда авторы хотят подчеркнуть, что знака не должно быть, это тоже веская причина использовать unsigned. И веская тоже потому, что код читают люди. Но при этом, я считаю, возникает дополнительная ответственность. Надо убедиться, что моделируемое число в предметной области никогда не должно быть отрицательным (чего часто не делают). Что при расчётах промежуточные результаты не уйдут за ноль. Что для передачи ошибки предусмотрен другой канал. А если всего этого не делают, то уж лучше использовать знаковое. Которое является просто максимально общим случаем. Избыточное обобщение не ошибка, а избыточное сужение — да.
Именно.
В последних 3-4 проектах, где богатый ресурсами, но embedded, я столкнулся с эффектом, которого раньше не видел. Есть до чёрта мест, где приходит, например, количество каналов в uint8_t. Что практически все кодеры делают — это цикл вида
То есть какого типа значение, такое выставляют и типу индекса.
Всё хорошо, но в одном месте произошло следующее. Пришло не количество каналов, а номер максимального канала. Есть те, кто любят именно такой стиль (я видел такое у Intel). Соответственно nchannels = max_channel + 1. И в реальности где дали 256 каналов цикл стал бесконечным.
Понятно, что это не проблема unsigned как такового, если знать, что он элемент поля по модулю. Это проблема качества анализа кодером (здесь это тот, кто написал код, неважно, какие ещё у него есть лычки и полномочия), что он не заметил, что именно тут переполняется возможное uint8_t. Но если бы это был честный unsigned, было бы несколько вариантов: например, статический анализатор нашёл бы проблему, или произошло бы исключение, если оно назначено для арифметики... а тут по факту любому анализатору усложнили жизнь, и никакой не пожаловался.
Смешно, но тот, кто это исправлял, первым делом загнал nchannels в переменную типа uint8_t Пришлось ещё раз фиксить.
A>К счастью, в большинстве случаев это неважно. Работать с коллекциями лучше в функциональном стиле, а размер вообще не считать числом.
Хм. Нам вот "налили" новый проект, а там... мнэээ, разработка началась этак в 2018, но там C процентов 95, и C++ остальных 5%. (Самое смешное, что туда лучше бы подошли Go или Erlang.)
Какой уж там функциональный стиль...