Хотя я глубоко сочувствую линии рассуждений Криса, я не соглашусь здесь (по крайней мере частично, я играю адвоката дьявола). Нет ничего плохого в использовании неподписанных типов для размеров, и это может быть даже полезно в некоторых обстоятельствах.
Крис оправдывает подписанные типы размеров тем, что они естественным образом используются в качестве индексов массивов, и вы можете захотеть сделать арифметику с индексами массивов, и эта арифметика может создавать временные значения, которые являются отрицательными.
Это нормально, и арифметика без знака не создает проблем при условии, что вы будете правильно интерпретировать свои значения при выполнении сравнений. Поскольку поведение переполнения целых чисел без знака полностью определено, временные переполнения в отрицательном диапазоне (или в огромные положительные числа) не вносят никаких ошибок, если они исправлены перед выполнением сравнения.
Иногда поведение переполнения является даже желательным, поскольку поведение переполнения арифметики без знака делает определенные проверки диапазона выразимыми как одно сравнение, которое в противном случае потребовало бы двух сравнений. Если я хочу проверить, находится ли x
в диапазоне [a,b]
и все ли значения без знака, я могу просто сделать:
if (x - a < b - a) {
}
Это не работает со знаковыми переменными; такие проверки диапазона довольно распространены для размеров и смещений массива.
Я упоминал ранее, что выгода в том, что арифметика переполнения имеет определенные результаты. Если ваша арифметика индекса переполняет подписанный тип, поведение определяется реализацией; нет способа сделать вашу программу переносимой. Используйте неподписанный тип, и эта проблема исчезнет. По общему признанию это относится только к огромным смещениям, но это касается некоторых применений.
В основном, возражения против неподписанных типов часто завышены. Реальная проблема заключается в том, что большинство программистов на самом деле не думают о точной семантике кода, который они пишут, и для небольших целочисленных значений подписанные типы ведут себя в большей степени в соответствии с их интуицией. Однако размеры данных растут довольно быстро. Когда мы имеем дело с буферами или базами данных, мы часто выходим за пределы диапазона «small», и переполнение со знаком гораздо более проблематично для правильной обработки, чем переполнение без знака. Решение заключается не в том, чтобы «не использовать неподписанные типы», а в том, чтобы «тщательно продумать код, который вы пишете, и убедиться, что вы его понимаете».