Я заметил, что современный код на C и C ++, кажется, использует size_t
вместо int
/ unsigned int
почти везде - от параметров для строковых функций C до STL. Мне любопытно узнать причину этого и преимущества, которые оно приносит.
Я заметил, что современный код на C и 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-документа .
size_t
могут представлять! Если нет, то кто?
Классический 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
? Это требует снижения производительности на некоторых платформах. Стандарт C требует, чтобы он long
занимал не менее 32 бит. Платформа IP16L32 реализует каждый 32-разрядный код в виде пары 16-разрядных слов. Почти всем 32-битным операторам на этих платформах требуются две инструкции, если не больше, потому что они работают с 32-битными в двух 16-битных блоках. Например, для перемещения 32-битной длины обычно требуются две машинные инструкции - по одной для перемещения каждой 16-битной порции.
Использование size_t
позволяет избежать потери производительности. Согласно этой фантастической статье , «Тип size_t
- это typedef, который является псевдонимом для некоторого целого типа без знака, как правило, unsigned int
или unsigned long
, возможно, даже unsigned long long
. Предполагается, что каждая реализация Standard C выбирает целое число без знака, которое достаточно велико - но не больше, чем нужно - представлять размер максимально возможного объекта на целевой платформе. "
unsigned int
и оно варьируется от одной системы к другой. Это должно быть как минимум 65536
, но обычно 4294967295
и может быть 18446744073709551615
(2 ** 64-1) в некоторых системах.
unsigned char
). Стандарт, кажется, нигде не содержит строку «65535» или «65536», а «+32767» встречается только (1.9: 9) в примечании как возможное наибольшее целое число, представимое в int
; гарантия не дается даже, что INT_MAX
не может быть меньше, чем это!
Тип 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
- я надеюсь, вы не имеете в виду это. Большую часть времени мы не имеем дело с массивами, где кардинальность адресного пространства + переносимость имеют значение. В этих случаях вы бы взяли size_t
. В любом другом случае вы берете индексы из (подписанных) целых чисел. Потому что путаница (которая приходит без предупреждения), возникающая из-за непредвиденного недопустимого поведения неподписанных, встречается чаще и хуже проблем переносимости, которые могут возникнуть в других случаях.
Тип size_t должен быть достаточно большим, чтобы хранить размер любого возможного объекта. Целое число без знака не должно удовлетворять этому условию.
Например, в 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, чтобы при компиляции библиотеки GNU C использовался тип unsigned для size_t. `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
должен быть достаточно большим, чтобы представлять размер самого большого отдельного объекта.