Разница между uint8 t, uint fast8 t и uint least8 t

стандарт C99 вводит следующие типы данных. Документацию можно найти здесь для библиотеки AVR stdint.

  • uint8_t означает, что это 8-битный беззнаковый тип.
  • uint_fast8_t означает, что это самый быстрый unsigned int с по крайней мере 8 биты.
  • uint_least8_t означает, что это unsigned int с по крайней мере 8 битами.

Я понимаю uint8_t и что такое uint_fast8_t( Я не знаю, как это реализовано в уровень регистрации).

1.Можете ли вы объяснить, что означает "это unsigned int С хотя бы 8 битами"?

2.Как!--1--> и uint_least8_t способствовать повышению эффективности кода по сравнению с uint8_t?

6 ответов


uint_least8_t - наименьший тип, который имеет не менее 8 бит. uint_fast8_t - самый быстрый тип, который имеет не менее 8 бит.

вы можете увидеть различия, представляя экзотические архитектуры. Представьте себе 20-битную архитектуру. Его unsigned int имеет 20 бит (один регистр), и его unsigned char имеет 10 бит. Так что sizeof(int) == 2, но через char типы требует дополнительных инструкций, чтобы сократить регистры пополам. Затем:

  • uint8_t: не определено (нет 8 бит тип.)
  • uint_least8_t: is unsigned char, наименьший тип, который составляет не менее 8 бит.
  • uint_fast8_t: is unsigned int, потому что в моей воображаемой архитектуре переменная с половиной регистра медленнее, чем с полным регистром.

uint8_t означает: дайте мне unsigned int ровно 8 бит.

uint_least8_t означает: дайте мне наименьший тип unsigned int, который имеет не менее 8 бит. Для оптимизации потребления памяти.

uint_fast8_t означает: дайте мне unsigned int не менее 8 бит. Выберите больший тип, если это сделает мою программу быстрее, из-за соображений выравнивания. Оптимизировать для скорости.

кроме того, в отличие от равнины int типы, подписанная версия вышеупомянутого stdint.ч типы гарантированный формат дополнения 2.


теория идет что-то вроде:

uint8_t требуется ровно 8 бит, но это не обязательно для существования. Поэтому вы должны использовать его там, где вы полагаетесь на арифметическое поведение по модулю 256 8-битного целого числа и где вы предпочли бы сбой компиляции неправильному поведению на неясных архитектурах.

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

uint_fast8_t предполагается, что это" самый быстрый " неподписанный тип, который может хранить не менее 8 бит; однако на самом деле это не гарантирует, что он будет самым быстрым для любой данной операции на любом данном процессоре. Вы бы использовали его в коде обработки, который выполняет множество операций над значением.

практика заключается в том, что" быстрые "и" наименее " типы не используются много.

" наименьшие " типы действительно полезны, только если вы заботитесь о переносимости чтобы скрыть архитектуры с помощью CHAR_BIT != 8 чего большинство людей не делают.

проблема с "быстрыми" типами заключается в том, что "быстрый" трудно придавить. Меньший тип может означать меньшую нагрузку на систему памяти / кэша, но использование меньшего типа может потребовать дополнительных инструкций. Кроме того, что лучше всего может измениться между версиями архитектуры, но разработчики часто хотят избежать нарушения ABI в таких случаях.

от просмотра некоторых популярных реализаций это кажется, что определения uint_fastn_t довольно произвольным. glibc, похоже, определяет их как по крайней мере" собственный размер слова " системы, о которой идет речь, не принимая во внимание тот факт, что многие современные процессоры (особенно 64-разрядные) имеют конкретную поддержку для быстрых операций над элементами, меньшими, чем их собственный размер слова. IOS, по-видимому, определяет их как эквивалентные типам фиксированного размера. Другие платформы могут отличаться.

все в всех если представление плотного кода с крошечными целыми числами ваша цель, вы должны быть bench-marking код код на платформах, которые вы заботитесь о с различными типами размера, чтобы увидеть, что работает лучше всего.


1.Можете ли вы объяснить, что означает "это unsigned int с по крайней мере 8 битами"?

это должно быть очевидно. Это означает, что это беззнаковый целочисленный тип, и что его ширина составляет не менее 8 бит. Фактически это означает, что он может, по крайней мере, удерживать числа от 0 до 255, и он определенно не может удерживать отрицательные числа, но он может быть в состоянии удерживать числа выше 255.

очевидно, что вы не должны использовать любой из этих типов, если вы планируете хранить любое число вне диапазона от 0 до 255 (и вы хотите, чтобы быть портативным).

2.Как uint_fast8_t и uint_least8_t помогают увеличить эффективность / пространство кода по сравнению с uint8_t?

uint_fast8_t требуется быть быстрее, поэтому вы должны использовать это, если ваше требование состоит в том, чтобы код был быстрым. uint_least8_t С другой стороны, требуется, чтобы не было кандидата меньшего размера - поэтому вы бы использовали это, если размер является проблемой.


и конечно, вы используете только uint8_t когда вам абсолютно необходимо, чтобы он был ровно 8 бит. Используя uint8_t может сделать non-портативный код uint8_t не требуется существовать (поскольку такой малый целочисленный тип не существует на определенных платформах).


некоторые процессоры не могут работать так же эффективно на небольших типах данных, как на больших. Например, дано:

uint32_t foo(uint32_t x, uint8_t y)
{
  x+=y;
  y+=2;
  x+=y;
  y+=4;
  x+=y;
  y+=6;
  x+=y;
  return x;
}

если y были uint32_t компилятор для ARM Cortex-M3 может просто генерировать

add r0,r0,r1,asl #2   ; x+=(y<<2)
add r0,r0,#12         ; x+=12
bx  lr                ; return x

но поскольку y is uint8_t компилятор должен был бы вместо этого генерировать:

add r0,r0,r1          ; x+=y
add r1,r1,#2          ; Compute y+2
and r1,r1,#255        ; y=(y+2) & 255
add r0,r0,r1          ; x+=y
add r1,r1,#4          ; Compute y+4
and r1,r1,#255        ; y=(y+4) & 255
add r0,r0,r1          ; x+=y
add r1,r1,#6          ; Compute y+6
and r1,r1,#255        ; y=(y+6) & 255
add r0,r0,r1          ; x+=y
bx  lr                ; return x

предназначение" быстрых " типов состояло в том, чтобы позволить компиляторам заменять меньшие типы, которые не могли быть эффективно обработаны быстрее те. К сожалению, семантика "быстрых" типов довольно плохо определена, что, в свою очередь, оставляет неясные вопросы о том, будут ли выражения оцениваться с помощью signed или unsigned math.


" быстрые " целочисленные типы определяются как самое быстрое целое число, доступное, по крайней мере, с требуемым количеством битов (в вашем случае 8).

платформа может определить uint_fast8_t as uint8_t тогда не будет абсолютно никакой разницы в скорости.

причина в том, что есть платформы, которые медленнее, когда не используют свою собственную длину слова.