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

437

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

Теги:
size-t

8 ответов

320
Лучший ответ

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

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

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

  • 48
    Нету. Подумайте о x86-16 с большой (не огромной) моделью памяти: указатели далеко (32-битные), но отдельные объекты ограничены 64 КБ (поэтому size_t может быть 16-битным).
  • 8
    «Размер самого большого объекта» не плохая формулировка, но абсолютно правильная. Шесть объектов может быть гораздо более ограниченной, чем адресное пространство.
Показать ещё 5 комментариев
87

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

Подробное описание на сайте embedded.com(с очень хорошим примером)

  • 4
    Еще одна замечательная статья, объясняющая как size_t, так и ptrdiff_t: viva64.com/en/a/0050
55

Короче говоря, size_t никогда не является отрицательным, и он максимизирует производительность, поскольку он typedef'd должен быть целым числом без знака, который достаточно большой - но не слишком большой - для представления размера максимально возможного объекта на целевой платформе.

Размеры никогда не должны быть отрицательными, и действительно, size_t является неподписанным типом. Кроме того, поскольку size_t не имеет знака, вы можете хранить числа, которые примерно в два раза больше, чем в соответствующем подписанном типе, потому что мы можем использовать битовый знак для представления величины, как и все остальные биты в целых числах без знака. Когда мы получаем еще один бит, мы умножаем диапазон чисел, которые мы можем представить примерно в два раза.

Итак, вы спрашиваете, почему бы просто не использовать unsigned int? Возможно, он не сможет удерживать достаточно большие цифры. В реализации, где unsigned int - 32 бита, наибольшее число, которое оно может представлять, равно 4294967295. Некоторые процессоры, такие как IP16L32, могут копировать объекты размером более 4294967295 байт.

Итак, вы спрашиваете, почему бы не использовать unsigned long int? Это повышает производительность на некоторых платформах. Стандарт C требует, чтобы a long занимал не менее 32 бит. Платформа IP16L32 реализует каждую 32-битную длину в виде пары 16-разрядных слов. Почти все 32-разрядные операторы на этих платформах требуют двух инструкций, если не больше, потому что они работают с 32 битами в двух 16-разрядных кусках. Например, для перемещения 32-битной длины обычно требуется две машинные команды - одна для перемещения каждого 16-разрядного фрагмента.

Использование size_t позволяет избежать этой производительности. Согласно эта фантастическая статья," Тип size_t является typedef, который является псевдонимом для некоторого целого числа без знака, обычно unsigned int или unsigned long, но, возможно, даже unsigned long long. Каждая реализация стандарта C должна выбирать целое число без знака, которое достаточно велико, но не больше, чем необходимо - для представления размера максимально возможного объекта на целевой платформе.

  • 1
    Извините, что прокомментировал это так долго, но мне просто нужно было подтвердить самое большое число, которое может содержать неподписанный int - возможно, я неправильно понимаю вашу терминологию, но я подумал, что самое большое число, которое может содержать unsigned int, это 4294967295, 65356 максимум неподписанного короткого.
  • 0
    Если ваш unsigned int занимает 32 бита, то да, самое большое число, которое он может содержать, это 2 ^ 32 - 1, что составляет 4294967295 (0xffffffff). У вас есть еще один вопрос?
Показать ещё 8 комментариев
48

Тип 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" ).

  • 0
    де-факто определение int состоит в том, что он 16-битный на 16 машинах и 32-битный на чем-то большем. Было написано слишком много кода, который предполагает, что int имеет ширину 32 бита, чтобы изменить это сейчас, и в результате люди всегда должны использовать size_t или {, u} int {8,16,32,64} _t, если они хотят что-то конкретное - - в качестве меры предосторожности люди должны всегда использовать их вместо целочисленных целочисленных типов.
  • 3
    «Это целое число без знака, способное выражать размер в байтах любого диапазона памяти, поддерживаемого на хост-машине». -> Нет. size_t может представлять размер любого отдельного объекта (например: число, массив, структура). Весь диапазон памяти может превышать size_t
22

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

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

  • 38
    «объект» - это язык, используемый стандартом.
  • 1
    Я думаю, что size_t должен был бы быть настолько большим, если бы компилятор мог принять тип X такой, что sizeof (X) даст значение больше 4G. Большинство компиляторов отклоняют, например, typedef unsigned char foo[1000000000000LL][1000000000000LL] и даже foo[65536][65536]; может быть законно отклонен, если он превысил задокументированный предел реализации.
Показать ещё 1 комментарий
3

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

2

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

  • 0
    Может быть определено как unsigned long для обоих случаев на некоторых ОС.
-3

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

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню