На моє розуміння, int
спочатку передбачалося, що це "рідний" цілочисельний тип з додатковою гарантією, що він повинен мати розмір принаймні 16 біт - те, що тоді вважалося "розумним" розміром.
Коли 32-розрядні платформи стали більш поширеними, можна сказати, що "розумний" розмір змінився на 32 біти:
- Сучасна Windows використовує 32-розрядну версію
int
версії на всіх платформах.
- POSIX гарантує
int
щонайменше 32 біти.
- C #, Java має тип,
int
який гарантовано становить рівно 32 біт.
Але коли 64-розрядна платформа стала нормою, ніхто не розширився int
і став 64-розрядним цілим числом через:
- Переносимість: багато коду залежить від
int
розміру 32 біта.
- Споживання пам'яті: подвоєне використання пам’яті для кожного
int
може бути нерозумним для більшості випадків, оскільки в більшості випадків кількість використовуваних набагато менше 2 мільярдів.
Тепер, чому ви б вважали за краще , uint32_t
щоб uint_fast32_t
? З тієї ж причини мови C # та Java завжди використовують цілі числа фіксованого розміру: програміст не пише код, думаючи про можливі розміри різних типів, вони пишуть для однієї платформи та тестують код на цій платформі. Більша частина коду неявно залежить від конкретних розмірів типів даних. І тому uint32_t
кращий вибір для більшості випадків - він не допускає жодної двозначності щодо своєї поведінки.
Більше того, чи uint_fast32_t
справді найшвидший тип на платформі розміром дорівнює або перевищує 32 біти? Не зовсім. Розглянемо цей компілятор коду GCC для x86_64 у Windows:
extern uint64_t get(void);
uint64_t sum(uint64_t value)
{
return value + get();
}
Створена збірка виглядає так:
push
sub $0x20,
mov
callq d <sum+0xd>
add
add $0x20,
pop
retq
Тепер, якщо ви зміните get()
значення повернення на uint_fast32_t
(яке становить 4 байти в Windows x86_64), ви отримаєте таке:
push %rbx
sub $0x20,%rsp
mov %rcx,%rbx
callq d <sum+0xd>
mov %eax,%eax ; <-- additional instruction
add %rbx,%rax
add $0x20,%rsp
pop %rbx
retq
Зверніть увагу, що згенерований код майже однаковий, за винятком додаткового mov %eax,%eax
інструкції після виклику функції, яка має розширити 32-бітове значення до 64-бітного.
Немає такої проблеми, якщо ви використовуєте лише 32-розрядні значення, але, ймовірно, ви будете використовувати ті зі size_t
змінними (розміри масиву, мабуть?), А це 64 біти на x86_64. У Linux uint_fast32_t
8 байт, тому ситуація інша.
Багато програмістів використовують, int
коли їм потрібно повернути невелике значення (скажімо, в діапазоні [-32,32]). Це було б чудово, якщоint
це буде власний цілий розмір платформ, але оскільки він не на 64-розрядних платформах, кращим вибором є інший тип, який відповідає нативному типу платформи (якщо він часто не використовується з іншими цілими числами менших розмірів).
В основному, незалежно від того, що говорить стандарт, uint_fast32_t
у будь-якому випадку реалізація порушена. Якщо ви дбаєте про додаткові інструкції, сформовані в деяких місцях, вам слід визначити свій власний "рідний" цілий тип. Або ви можете використовувати size_t
для цієї мети, оскільки вона, як правило, відповідає native
розміру (я не включаю старі та незрозумілі платформи, такі як 8086, лише платформи, які можуть запускати Windows, Linux тощо).
Ще однією ознакою, яка показує, що int
мав бути власний цілочисельний тип, є "правило цілочисельного просування". Більшість центральних процесорів можуть виконувати операції лише з власними, тому 32-бітовий центральний процесор зазвичай може виконувати лише 32-розрядні додавання, віднімання тощо (процесори Intel тут є винятком). Цілі цілі інших розмірів підтримуються лише за допомогою інструкцій щодо завантаження та зберігання. Наприклад, 8-бітове значення повинно бути завантажено з відповідною інструкцією "завантажити 8-бітовий підпис" або "завантажити 8-бітове беззнакове" і після завантаження значення буде розширено до 32 біт. Без цілочисельного правила просування компіляторам С потрібно було б додати трохи більше коду для виразів, що використовують типи, менші за рідний тип. На жаль, це більше не стосується 64-розрядних архітектур, оскільки компіляторам тепер доводиться видавати додаткові інструкції в деяких випадках (як було показано вище).