Тип size_t
определяется как целочисленный тип без знака оператора sizeof
. В реальном мире вы часто будете видеть int
, определенный как 32 бита (для обратной совместимости), но size_t
, определенный как 64 бита (так что вы можете объявить массивы и структуры размером более 4 ГиБ) на 64-битных платформах. Если long int
также является 64-битным, это называется соглашением LP64; если long int
равен 32 битам, но long long int
, а указатели 64-битные, это LLP64. Вы также можете получить обратную, программу, которая использует 64-битные инструкции для скорости, но 32-битные указатели для экономии памяти. Кроме того, int
подписано, а size_t
- без знака.
Исторически было много других платформ, где адреса были шире или короче, чем собственный размер int
. Фактически, в 70-х и в начале 80-х это было более распространенным, чем нет: все популярные 8-битные микрокомпьютеры имели 8-битные регистры и 16-битные адреса, а переход между 16 и 32-битными также породил множество машин, которые адреса были шире, чем их регистры. Я иногда до сих пор вижу здесь вопросы о Borland Turbo C для MS-DOS, чей режим памяти Huge содержал 20-битные адреса, хранящиеся в 32-битном режиме на 16-битном процессоре (но который мог поддерживать 32-битный набор команд 80386); Motorola 68000 имел 16-битный ALU с 32-битными регистрами и адресами; были мэйнфреймы IBM с 15-, 24- или 31-разрядными адресами. Вы также все еще видите различные размеры ALU и адресной шины во встроенных системах.
В любое время int
меньше, чем size_t
, и вы пытаетесь сохранить размер или смещение очень большого файла или объекта в unsigned int
, есть вероятность, что он может переполниться и вызвать ошибку. С int
также есть возможность получить отрицательное число. Если int
или unsigned int
шире, программа будет работать правильно, но тратит память.
Обычно вы должны использовать правильный тип для этой цели, если вам нужна переносимость. Многие люди рекомендуют использовать математику со знаком вместо без знака (чтобы избежать неприятных, тонких ошибок, таких как 1U < -3
). Для этой цели стандартная библиотека определяет ptrdiff_t
в <stddef.h>
как тип со знаком результата вычитания указателя из другого.
Тем не менее, обходной путь может заключаться в том, чтобы ограничить проверку всех адресов и смещений по INT_MAX
и либо 0
или INT_MIN
, в зависимости от ситуации, и включить предупреждения компилятора о сравнении подписанных и неподписанных величин в случае пропуска любой. В любом случае вы всегда должны всегда проверять доступ к массиву на предмет переполнения в Си.