Без знака 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'ssys/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'ssys/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++ (по крайней мере, по умолчанию).

Другие вопросы по тегам