unsigned int vs. size_t

Я замечаю, что современный C и C ++ код, кажется, использует size_t вместо int / unsigned int почти везде – от параметров для строковых функций C до STL. Мне любопытно узнать причину этого и преимущества, которые он приносит.

Тип size_t – это целочисленный тип без знака, который является результатом оператора sizeof (и оператора offsetof ), поэтому он может быть достаточно большим, чтобы содержать размер самого большого объекта, который может обрабатывать ваша система (например, статический массив 8Gb).

Тип size_t может быть больше, равно или меньше, чем unsigned int , и ваш компилятор может сделать предположения об этом для оптимизации.

Вы можете найти более точную информацию в стандарте C99, раздел 7.17, проект которого доступен в Интернете в формате pdf или в стандарте C11, раздел 7.19, также доступен в виде pdf-проекта .

Классический C (ранний диалект C, описанный Брайаном Керниганом и Деннисом Ритчи на языке программирования C, Prentice-Hall, 1978) не предоставил size_t . Комитет по стандартизации C представил size_t для устранения проблемы переносимости

Подробное объяснение на сайте embedded.com (с очень хорошим примером)

Короче говоря, size_t никогда не является отрицательным, и он максимизирует производительность, потому что typedef’d является неподписанным целым типом, который достаточно большой, но не слишком большой, чтобы представлять размер максимально возможного объекта на целевой платформе.

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

Итак, вы спрашиваете, почему бы просто не использовать unsigned int ? Возможно, он не сможет удерживать достаточно большие цифры. В реализации, где unsigned int – 32 бита, наибольшее число, которое он может представлять, – 4294967295 . Некоторые процессоры, такие как IP16L32, могут копировать объекты размером более 4294967295 байт.

Итак, вы спрашиваете, почему бы не использовать unsigned long int ? Это повышает производительность на некоторых платформах. Стандарт C требует, чтобы long занимали не менее 32 бит. Платформа IP16L32 реализует каждую 32-битную длину в виде пары 16-разрядных слов. Почти все 32-разрядные операторы на этих платформах требуют двух инструкций, если не больше, потому что они работают с 32 битами в двух 16-разрядных кусках. Например, для перемещения 32-битной длины обычно требуется две машинные команды – одна для перемещения каждого 16-разрядного fragmentа.

Использование size_t позволяет избежать этой производительности. Согласно этой фантастической статье : «Тип size_t – это typedef, который является псевдонимом для какого-то целого числа без знака, как правило, unsigned int или unsigned long , но, возможно, даже unsigned long long . Каждая реализация Standard C должна выбирать целое число без знака, которое достаточно велико, – но не больше, чем нужно – представлять размер максимально возможного объекта на целевой платформе ».

Тип size_t – это тип, возвращаемый оператором sizeof. Это целое число без знака, способное выражать размер в байтах любого диапазона памяти, поддерживаемого на главной машине. Он (как правило) связан с ptrdiff_t в том, что ptrdiff_t является знаковым целочисленным значением, так что sizeof (ptrdiff_t) и sizeof (size_t) равны.

При написании кода C вы всегда должны использовать size_t, когда имеете дело с диапазонами памяти.

Тип int, с другой стороны, в основном определяется как размер (подписанного) целочисленного значения, которое хост-машина может использовать для наиболее эффективного выполнения целочисленной арифметики. Например, на многих компьютерах с более старыми компьютерами значение sizeof (size_t) будет 4 (байты), а sizeof (int) будет 2 (байт). 16-разрядная арифметика была быстрее, чем 32-разрядная арифметика, хотя ЦП мог обрабатывать (логическое) пространство памяти до 4 ГБ.

Используйте тип int только тогда, когда вы заботитесь об эффективности, поскольку его фактическая точность сильно зависит от параметров компилятора и архитектуры машины. В частности, в стандарте C задаются следующие инварианты: sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long), не устанавливая никаких других ограничений на фактическое представление точности, доступной программисту для каждого из эти примитивные типы.

Примечание. Это не то же самое, что и в Java (которое фактически определяет точность бит для каждого из типов «char», «byte», «short», «int» и «long»).

Тип size_t должен быть достаточно большим, чтобы хранить размер любого возможного объекта. Unsigned int не должен удовлетворять этому условию.

Например, в 64-битных системах int и unsigned int могут быть 32 бит в ширину, но size_t должен быть достаточно большим, чтобы хранить числа, большие, чем 4G

Этот отрывок из руководства пользователя glibc 0,02 может также иметь значение при исследовании темы:

Существует потенциальная проблема с типом size_t и версиями GCC до выпуска 2.4. ANSI C требует, чтобы size_t всегда был неподписанным. Для совместимости с заголовочными файлами существующих систем GCC определяет size_t в stddef.h' to be whatever type the system's sys / types.h’ системы, который определяет его. Большинство Unix-систем, которые определяют size_t в `sys / types.h ‘, определяют его как подписанный тип. Некоторый код в библиотеке зависит от того, какой size_t является неподписанным, и не будет работать правильно, если он подписан.

Код библиотеки GNU C, который ожидает, что size_t будет неподписанным, верен. Неверное определение size_t как подписанного типа. Мы планируем, что в версии 2.4 GCC всегда будет определять size_t как неподписанный тип, а fixincludes' script will massage the system's sys / types.h, чтобы не противоречить этому.

Тем временем мы обходим эту проблему, явно указывая GCC на использование неподписанного типа для size_t при компиляции библиотеки GNU C. `configure ‘автоматически обнаружит, какой тип GCC использует для size_t, чтобы его переопределить, если это необходимо.

Если мой компилятор настроен на 32 бит, size_t – это не что иное, как typedef для unsigned int . Если мой компилятор настроен на 64 бит, size_t – это не что иное, как typedef для unsigned long long .

size_t – размер указателя.

Таким образом, в 32 битах или общей модели ILP32 (целочисленный, длинный, указательный) size_t составляет 32 бита. а в 64 бит или общая модель LP64 (long, pointer) size_t – 64 бита (целые числа по-прежнему 32 бита).

Существуют и другие модели, но это те, которые используют g ++ (по крайней мере, по умолчанию)

Давайте будем гением компьютера.