Я заметил, что современный код на 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 int32 бита, наибольшее число, которое он может представлять, - 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'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.
unsigned longдля обоих случаев на некоторых ОС.
size_t - размер указателя.
Таким образом, в 32-битной или общей ILP32 (целое, длинное, указатель) модель size_t составляет 32 бита. и в 64-битной или обычной модели LP64 (long, pointer) size_t равен 64 битам (целые числа по-прежнему 32 бит).
Существуют и другие модели, но именно они используют g ++ (по крайней мере, по умолчанию).
size_tне обязательно такой же размер, как указатель, хотя обычно это так. Указатель должен указывать на любое место в памяти; size_tдолжен быть достаточно большим, чтобы представлять размер самого большого отдельного объекта.