Unsigned int vs. size_t

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

Ответ 1

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

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

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

Ответ 3

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

Размеры никогда не должны быть отрицательными, и действительно 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-битного блока.

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

Ответ 4

Тип 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" ).

Ответ 5

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

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

Ответ 6

Эта выдержка из руководства пользователя 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, чтобы его переопределить, если это необходимо.

Ответ 7

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

Ответ 8

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

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

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