Я замечаю, что современный код на 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 требует, чтобы a long
занимал не менее 32 бит. Платформа IP16L32 реализует каждую 32-битную длину в виде пары 16-разрядных слов. Почти все 32-разрядные операторы на этих платформах требуют двух инструкций, если не больше, потому что они работают с 32 битами в двух 16-разрядных кусках. Например, для перемещения 32-битной длины обычно требуется две машинные команды - одна для перемещения каждого 16-разрядного фрагмента.
Использование size_t позволяет избежать этой производительности. Согласно эта фантастическая статья," Тип size_t является typedef, который является псевдонимом для некоторого целого числа без знака, обычно unsigned int или unsigned long, но, возможно, даже unsigned long long. Каждая реализация стандарта 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
может представлять размер любого отдельного объекта (например: число, массив, структура). Весь диапазон памяти может превышать size_t
Тип size_t должен быть достаточно большим, чтобы хранить размер любого возможного объекта. Unsigned int не должен удовлетворять этому условию.
Например, в 64-битных системах int и unsigned int могут быть 32 бит в ширину, но size_t должен быть достаточно большим, чтобы хранить числа больше 4G
size_t
должен был бы быть настолько большим, если бы компилятор мог принять тип X такой, что sizeof (X) даст значение больше 4G. Большинство компиляторов отклоняют, например, typedef unsigned char foo[1000000000000LL][1000000000000LL]
и даже foo[65536][65536];
может быть законно отклонен, если он превысил задокументированный предел реализации.
Эта выдержка из руководства пользователя 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.
unsigned long
для обоих случаев на некоторых ОС.
size_t - размер указателя.
Таким образом, в 32 битах или общей модели ILP32 (целочисленный, длинный, указательный) size_t составляет 32 бита. и в 64 бит или общая модель LP64 (long, pointer) size_t имеет 64 бита (целые числа по-прежнему 32 бита).
Существуют и другие модели, но это те, которые используют g++ (по крайней мере по умолчанию)
size_t
не обязательно совпадает с размером указателя, хотя обычно это так. Указатель должен указывать на любое место в памяти; size_t
должен быть достаточно большим, чтобы представлять размер самого большого отдельного объекта.