без знака int против size_t - PullRequest
       34

без знака int против size_t

466 голосов
/ 25 сентября 2008

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

Ответы [ 8 ]

365 голосов
/ 25 сентября 2008

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

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

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

92 голосов
/ 25 сентября 2008

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

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

68 голосов
/ 28 ноября 2010

Короче говоря, 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 имеет вид должен выбрать целое число без знака, которое достаточно велико - но не больше необходимого - для представления размера максимально возможного объекта на целевой платформе. "

48 голосов
/ 25 сентября 2008

Тип 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), не накладывая никаких других ограничений на фактическое представление точности, доступной программисту для каждого из эти примитивные типы. </p>

Примечание: это НЕ то же самое, что в Java (которая фактически определяет битовую точность для каждого из типов 'char', 'byte', 'short', 'int' и 'long').

23 голосов
/ 25 сентября 2008

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

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

3 голосов
/ 24 сентября 2013

Этот отрывок из руководства 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 использовать тип unsigned для size_t при компиляции библиотеки GNU C. `configure 'автоматически определит, какой тип GCC использует для size_t, чтобы переопределить его при необходимости.

1 голос
/ 19 января 2016

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

0 голосов
/ 27 сентября 2008

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

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

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

...