Без знака int против size_t
Я заметил, что современный код на C и C++, похоже, использует size_t
вместо int
/unsigned int
почти везде - от параметров для строковых функций Си до STL. Мне любопытно узнать причину этого и преимущества, которые оно приносит.
8 ответов
size_t
тип - это целое число без знака, являющееся результатом sizeof
оператор (и offsetof
оператор), поэтому он гарантированно будет достаточно большим, чтобы вместить в себя размер самого большого объекта, который может обработать ваша система (например, статический массив 8 Гб).
size_t
Тип может быть больше, равно или меньше, чем unsigned int
и ваш компилятор может сделать предположения об этом для оптимизации.
Вы можете найти более точную информацию в стандарте C99, раздел 7.17, черновой вариант которого доступен в Интернете в формате pdf, или в стандарте C11, раздел 7.19, который также доступен в виде PDF-документа.
Классический C (ранний диалект C, описанный Брайаном Керниганом и Деннисом Ритчи в The C Programming Language, 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
? Это требует снижения производительности на некоторых платформах. Стандарт С требует, чтобы 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 должен быть достаточно большим, чтобы хранить размер любого возможного объекта. Целое число без знака не должно удовлетворять этому условию.
Например, в 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, чтобы при компиляции библиотеки GNU C использовался тип unsigned для size_t. `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++ (по крайней мере, по умолчанию).