c++ - uint16_t - uint32_t c
Diferencia entre uint8_t, uint_fast8_t y uint_least8_t (6)
1. ¿Puede explicar cuál es el significado de "es un int sin signo con al menos 8 bits"?
Eso debería ser obvio. Significa que es un tipo entero sin signo y que su ancho es de al menos 8 bits. En efecto, esto significa que al menos puede contener los números del 0 al 255, y definitivamente no puede contener números negativos, pero puede contener números superiores a 255.
Obviamente, no debe usar ninguno de estos tipos si planea almacenar cualquier número fuera del rango de 0 a 255 (y desea que sea portátil).
2.¿Cómo ayudan uint_fast8_t y uint_least8_t a aumentar la eficiencia / espacio de código en comparación con uint8_t?
Se requiere que
uint_fast8_t
sea โโmás rápido, por lo que debe usarlo si su requisito es que el código sea rápido.
uint_least8_t
por otro lado, requiere que no haya ningún candidato de menor tamaño, por lo que lo usaría si el tamaño es la preocupación.
Y, por supuesto, solo usa
uint8_t
cuando es absolutamente necesario que sea exactamente 8 bits.
El uso de
uint8_t
puede hacer que el código no sea portátil ya que no es necesario que exista
uint8_t
(porque ese tipo de entero pequeño no existe en ciertas plataformas).
El estándar C99 presenta los siguientes tipos de datos. La documentación se puede encontrar here para la biblioteca estándar AVR.
-
uint8_t
significa que es un tipo sin signo de 8 bits. -
uint_fast8_t
significa que es el int sin signo más rápido con al menos 8 bits. -
uint_least8_t
significa que es un int sin signo con al menos 8 bits.
Entiendo
uint8_t
y qué es
uint_fast8_t
(no sé cómo se implementa en el nivel de registro).
1. ¿Puede explicar cuál es el significado de "es un
unsigned int
con al menos 8 bits"?
2.¿Cómo
uint_fast8_t
y
uint_least8_t
a aumentar la eficiencia / espacio de código en comparación con
uint8_t
?
Algunos procesadores no pueden funcionar de manera tan eficiente en tipos de datos más pequeños como en los grandes. Por ejemplo, dado:
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;
}
si fuera
uint32_t
un compilador para ARM Cortex-M3 simplemente podría generar
add r0,r0,r1,asl #2 ; x+=(y<<2)
add r0,r0,#12 ; x+=12
bx lr ; return x
pero como
y
es
uint8_t
el compilador tendría que generar en su lugar:
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
El propósito de los tipos "rápidos" era permitir que los compiladores reemplazaran los tipos más pequeños que no podían procesarse eficientemente con los más rápidos. Desafortunadamente, la semántica de los tipos "rápidos" está bastante poco especificada, lo que a su vez deja preguntas confusas sobre si las expresiones se evaluarán usando matemáticas con o sin signo.
La teoría es algo así como:
Se requiere que
uint8_t
tenga exactamente 8 bits, pero no es necesario que exista.
Por lo tanto, debe usarlo cuando confía en el comportamiento de asignación del módulo 256 * de un entero de 8 bits y donde prefiere una falla de compilación por mal comportamiento en arquitecturas oscuras.
Se requiere que
uint_least8_t
sea โโel tipo entero sin signo más pequeño disponible que pueda almacenar al menos 8 bits.
Lo usaría cuando quiera minimizar el uso de memoria de cosas como grandes matrices.
Se supone que
uint_fast8_t
es el tipo sin signo "más rápido" que puede almacenar al menos 8 bits;
sin embargo, en realidad no se garantiza que sea el más rápido para cualquier operación en un procesador dado.
Lo usaría en el código de procesamiento que realiza muchas operaciones en el valor.
La práctica es que los tipos "rápido" y "mínimo" no se usan mucho.
Los tipos "menos" solo son realmente útiles si le importa la portabilidad para oscurecer arquitecturas con CHAR_BIT! = 8, lo que no le gusta a la mayoría de las personas.
El problema con los tipos "rápidos" es que "más rápido" es difícil de precisar. Un tipo más pequeño puede significar menos carga en el sistema de memoria / caché, pero el uso de un tipo que es más pequeño que el nativo puede requerir instrucciones adicionales. Además, lo que es mejor puede cambiar entre versiones de arquitectura, pero los implementadores a menudo quieren evitar romper la ABI en tales casos.
Al observar algunas implementaciones populares, parece que las definiciones de uint_fastn_t son bastante arbitrarias. glibc parece definirlos como al menos el "tamaño de palabra nativa" del sistema en cuestión sin tener en cuenta el hecho de que muchos procesadores modernos (especialmente los de 64 bits) tienen soporte específico para operaciones rápidas en elementos más pequeños que su palabra nativa tamaño. IOS aparentemente los define como equivalentes a los tipos de tamaño fijo. Otras plataformas pueden variar.
En general, si su objetivo es el rendimiento de código apretado con números enteros pequeños, debe realizar una evaluación comparativa de su código en las plataformas que le interesan con diferentes tipos de tamaños para ver qué funciona mejor.
* Tenga en cuenta que, lamentablemente, el comportamiento de asignación de módulo 256 no siempre implica aritmética de módulo 256, gracias a la mala función de promoción de enteros de C.
Los tipos enteros "rápidos" se definen como el número entero más rápido disponible con al menos la cantidad de bits necesarios (en su caso 8).
Una plataforma puede definir
uint_fast8_t
como
uint8_t
entonces no habrá absolutamente ninguna diferencia en la velocidad.
La razón es que hay plataformas que son más lentas cuando no usan su longitud de palabra nativa.
uint8_t
significa: dame un int sin signo de exactamente 8 bits.
uint_least8_t
significa: dame el tipo más pequeño de int sin signo que tiene al menos 8 bits.
Optimizar para el consumo de memoria.
uint_fast8_t
significa: dame un int sin signo de al menos 8 bits.
Elija un tipo más grande si hará que mi programa sea más rápido, debido a consideraciones de alineación.
Optimizar para la velocidad.
Además, a diferencia de los tipos
int
simples, la versión firmada de los tipos stdint.h anteriores está garantizada como formato de complemento a 2.
uint_least8_t
es el tipo más pequeño que tiene al menos 8 bits.
uint_fast8_t
es el tipo más rápido que tiene al menos 8 bits.
Puedes ver las diferencias imaginando arquitecturas exóticas.
Imagine una arquitectura de 20 bits.
Su
unsigned int
tiene 20 bits (un registro) y su
unsigned char
tiene 10 bits.
Entonces
sizeof(int) == 2
, pero usar tipos de caracteres requiere instrucciones adicionales para cortar los registros a la mitad.
Entonces:
-
uint8_t
: no está definido (no hay tipo de 8 bits). -
uint_least8_t
: esunsigned char
, el tipo más pequeño que tiene al menos 8 bits. -
uint_fast8_t
: esunsigned int
, porque en mi arquitectura imaginaria, una variable de medio registro es más lenta que una de registro completo.