sirve que para long float definicion data c++ c int

c++ - que - ¿Por qué se preferiría uint32_t en lugar de uint_fast32_t?



long long c++ range (11)

¿Por qué muchas personas usan uint32_t lugar de uint32_fast_t ?

Nota: El nombre uint32_fast_t debe ser uint_fast32_t .

uint32_t tiene una especificación más estricta que uint_fast32_t y, por lo tanto, ofrece una funcionalidad más consistente.

uint32_t pros:

  • Varios algoritmos especifican este tipo. OMI: la mejor razón para usar.
  • Ancho y rango exactos conocidos.
  • Las matrices de este tipo no generan desperdicio.
  • la matemática entera sin signo con su desbordamiento es más predecible.
  • Coincidencia más estrecha en el rango y las matemáticas de los tipos de 32 bits de otros idiomas.
  • Nunca acolchado.

uint32_t contras:

  • No siempre está disponible (sin embargo, esto es raro en 2018).
    Por ejemplo: plataformas que carecen de enteros de 8/16/32 bits (9/18/36 bits, others ).
    Por ejemplo: plataformas que usan un complemento que no es 2. viejo 2200

uint_fast32_t pros:

  • Siempre disponible.
    Esto siempre permite que todas las plataformas, nuevas y antiguas, usen tipos rápidos / mínimos.
  • Tipo "Fastest" que admite un rango de 32 bits.

uint_fast32_t contras:

  • El alcance es mínimamente conocido. Ejemplo, podría ser un tipo de 64 bits.
  • Las matrices de este tipo pueden ser un desperdicio de memoria.
  • Todas las respuestas (las mías también al principio), la publicación y los comentarios usaron el nombre incorrecto uint32_fast_t . Parece que muchos simplemente no necesitan y usan este tipo. ¡Ni siquiera usamos el nombre correcto!
  • Relleno posible - (raro).
  • En casos seleccionados, el tipo "más rápido" realmente puede ser otro tipo. Entonces uint_fast32_t es solo una aproximación de primer orden.

Al final, lo mejor depende del objetivo de codificación. A menos que codifique para una portabilidad muy amplia o alguna función de rendimiento, use uint32_t .

Hay otro problema al usar estos tipos que entra en juego: su rango en comparación con int/unsigned

Presumiblemente, uint_fastN_t sería al menos el rango de unsigned . Esto no se especifica, pero es una condición cierta y comprobable.

Por lo tanto, uintN_t es más probable que uint_fastN_t sea ​​más angosto que el unsigned . Esto significa que el código que usa uintN_t matemáticas uintN_t está más sujeto a promociones de enteros que uint_fastN_t cuando se trata de portabilidad.

Con esta preocupación: ventaja de portabilidad uint_fastN_t con operaciones matemáticas seleccionadas.

Nota al int32_t sobre int32_t lugar de int_fast32_t : en máquinas raras, INT_FAST32_MIN puede ser -2,147,483,647 y no -2,147,483,648. El punto más grande: (u)intN_t tipos (u)intN_t están bien especificados y conducen a un código portátil.

Parece que uint32_t es mucho más frecuente que uint_fast32_t (me doy cuenta de que esto es evidencia anecdótica). Sin embargo, eso me parece contrario a la intuición.

Casi siempre que veo que una implementación usa uint32_t , todo lo que realmente quiere es un número entero que pueda contener valores de hasta 4,294,967,295 (generalmente un límite mucho más bajo en algún lugar entre 65,535 y 4,294,967,295).

Parece extraño usar uint32_t , ya que no se necesita la garantía ''exactamente 32 bits'' , y la garantía ''más rápida disponible> = 32 bits'' de uint_fast32_t parece ser exactamente la idea correcta. Además, aunque generalmente se implementa, no se garantiza que uint32_t exista.

¿Por qué, entonces, se uint32_t ? ¿Es simplemente más conocido o hay ventajas técnicas sobre el otro?


¿Por qué muchas personas usan uint32_t lugar de uint32_fast_t ?

Respuesta tonta:

  • No hay un tipo estándar uint32_fast_t , la ortografía correcta es uint_fast32_t .

Respuesta práctica:

  • Muchas personas realmente usan uint32_t o int32_t por su semántica precisa, exactamente 32 bits con aritmética sin signo ( uint32_t ) o representación de complemento a 2 ( int32_t ). Los tipos xxx_fast32_t pueden ser más grandes y, por lo tanto, inapropiados para almacenarlos en archivos binarios, usarlos en matrices y estructuras empaquetadas o enviarlos a través de una red. Además, puede que ni siquiera sean más rápidos.

Respuesta pragmática:

  • Muchas personas simplemente no saben (o simplemente no les importa) sobre uint_fast32_t , como se demuestra en los comentarios y respuestas, y probablemente suponen que unsigned int tiene la misma semántica, aunque muchas arquitecturas actuales todavía tienen int s de 16 bits y algunas Las muestras raras del museo tienen otros tamaños int extraños menores de 32.

Respuesta UX:

  • Aunque posiblemente sea más rápido que uint32_t , uint_fast32_t es más lento de usar: toma más tiempo escribir, especialmente teniendo en cuenta la búsqueda de ortografía y semántica en la documentación de C ;-)

La elegancia importa (obviamente basada en la opinión):

  • uint32_t ve tan mal que muchos programadores prefieren definir su propio tipo u32 o uint32 ... Desde esta perspectiva, uint_fast32_t parece torpe sin uint_fast32_t reparación. No es de extrañar que se uint_least32_t en el banco con sus amigos uint_least32_t y tal.

En muchos casos, cuando un algoritmo funciona en una matriz de datos, la mejor manera de mejorar el rendimiento es minimizar el número de errores de caché. Cuanto más pequeño es cada elemento, más pueden caber en el caché. Esta es la razón por la que todavía se escribe mucho código para usar punteros de 32 bits en máquinas de 64 bits: no necesitan nada cercano a 4 GiB de datos, pero el costo de hacer que todos los punteros y compensaciones necesiten ocho bytes en lugar de cuatro Sería sustancial.

También hay algunos ABI y protocolos especificados para necesitar exactamente 32 bits, por ejemplo, direcciones IPv4. Eso es lo que uint32_t realmente significa: usar exactamente 32 bits, independientemente de si eso es eficiente en la CPU o no. Estos solían declararse como long o unsigned long , lo que causó muchos problemas durante la transición de 64 bits. Si solo necesita un tipo sin signo que contenga números de al menos 2³²-1, esa ha sido la definición unsigned long desde que salió el primer estándar C. Sin embargo, en la práctica, el código antiguo suficiente suponía que a long podía contener cualquier puntero o desplazamiento de archivo o marca de tiempo, y el código antiguo suficiente suponía que tenía exactamente 32 bits de ancho, que los compiladores no necesariamente pueden hacer long lo mismo int_fast32_t sin romper demasiadas cosas.

En teoría, sería más a prueba de futuro para un programa usar uint_least32_t , y tal vez incluso cargar uint_least32_t elementos en una uint_fast32_t variable para realizar cálculos. ¡Una implementación que no tenía ningún uint32_t tipo podría incluso declararse en cumplimiento formal del estándar! (Simplemente no sería capaz de compilar muchos programas existentes.) En la práctica, no hay arquitectura ya dónde int , uint32_t y uint_least32_t no son los mismos, y ninguna ventaja, actualmente , a la realización de uint_fast32_t . Entonces, ¿por qué complicar demasiado las cosas?

Sin embargo, mire la razón por la que todos los 32_t tipos necesitaban existir cuando ya la teníamos long , y verá que esas suposiciones han explotado en nuestras caras antes. Su código podría terminar ejecutándose algún día en una máquina donde los cálculos de ancho exacto de 32 bits sean más lentos que el tamaño de la palabra nativa, y habría sido mejor usarlo uint_least32_t para el almacenamiento y el uint_fast32_t cálculo religioso. O si cruzará ese puente cuando llegue a él y solo quiera algo simple, hay unsigned long .


Para dar una respuesta directa: creo que la verdadera razón por la que uint32_t se usa uint_fast32_t o uint_least32_t simplemente es que es más fácil de escribir y, debido a que es más corto, mucho más agradable de leer: si crea estructuras con algunos tipos, y algunos de ellos son uint_fast32_t o similar, entonces a menudo es difícil alinearlos bien con int u bool otros tipos en C, que son bastante cortos (caso en punto: char vs. character ). Por supuesto, no puedo respaldar esto con datos duros, pero las otras respuestas solo pueden adivinar la razón también.

En cuanto a las razones técnicas para preferir uint32_t , no creo que existan, cuando absolutamente necesita un int sin signo exacto de 32 bits, entonces este tipo es su única opción estandarizada. En casi todos los demás casos, las otras variantes son técnicamente preferibles, específicamente, uint_fast32_t si le preocupa la velocidad y uint_least32_t si le preocupa el espacio de almacenamiento. El uso uint32_t en cualquiera de estos casos corre el riesgo de no poder compilar ya que no es necesario que exista el tipo.

En la práctica, los uint32_t tipos relacionados y existen en todas las plataformas actuales, excepto algunos DSP muy raros (hoy en día) o implementaciones de broma, por lo que hay poco riesgo real al usar el tipo exacto. Del mismo modo, si bien puedes encontrar penalizaciones de velocidad con los tipos de ancho fijo, ya no son (en los cpus modernos) paralizantes.

Por eso, creo, el tipo más corto simplemente gana en la mayoría de los casos, debido a la flojera del programador.


Desde el punto de vista de la corrección y la facilidad de codificación, uint32_t tiene muchas ventajas sobre uint_fast32_t en particular debido al tamaño definido con mayor precisión y la semántica aritmética, como han señalado muchos usuarios anteriores.

Lo que tal vez se haya perdido es que la supuesta ventaja de uint_fast32_t que puede ser más rápido , pero nunca se materializó de manera significativa. La mayoría de los procesadores de 64 bits que han dominado la era de 64 bits (x86-64 y Aarch64 en su mayoría) evolucionaron a partir de arquitecturas de 32 bits y tienen operaciones nativas rápidas de 32 bits incluso en modo de 64 bits. Entonces uint_fast32_t es igual que uint32_t en esas plataformas.

Incluso si algunas de las plataformas "también ejecutadas" como POWER, MIPS64, SPARC solo ofrecen operaciones de ALU de 64 bits, la gran mayoría de las operaciones interesantes de 32 bits se pueden realizar perfectamente en registros de 64 bits: la parte inferior de 32 bits funcionará tener los resultados deseados (y todas las plataformas principales al menos le permiten cargar / almacenar 32 bits). El desplazamiento a la izquierda es el principal problema, pero incluso eso puede optimizarse en muchos casos mediante optimizaciones de seguimiento de valor / rango en el compilador.

Dudo que ocasionalmente el desplazamiento a la izquierda un poco más lento o la multiplicación 32x32 -> 64 supere el doble del uso de memoria para dichos valores, en todas las aplicaciones, excepto en las más oscuras.

Finalmente, notaré que si bien la compensación se ha caracterizado en gran medida como "uso de memoria y potencial de vectorización" (a favor de uint32_t ) versus conteo / velocidad de instrucciones (a favor de uint_fast32_t ), incluso eso no está claro para mí. Sí, en algunas plataformas necesitará instrucciones adicionales para algunas operaciones de 32 bits, pero también guardará algunas instrucciones porque:

  • El uso de un tipo más pequeño a menudo permite que el compilador combine inteligentemente operaciones adyacentes mediante el uso de una operación de 64 bits para lograr dos de 32 bits. Un ejemplo de este tipo de "vectorización del pobre" no es infrecuente. Por ejemplo, cree una struct two32{ uint32_t a, b; } constante struct two32{ uint32_t a, b; } struct two32{ uint32_t a, b; } en rax como two32{1, 2} se puede optimizar en un solo mov rax, 0x20001 mientras que la versión de 64 bits necesita dos instrucciones. En principio, esto también debería ser posible para operaciones aritméticas adyacentes (misma operación, operando diferente), pero no lo he visto en la práctica.
  • Un "uso de memoria" más bajo a menudo también lleva a menos instrucciones, incluso si la huella de memoria o caché no es un problema, ya que cualquier estructura de tipo o matrices de este tipo se copian, obtienes el doble de dinero por cada dólar copiado.
  • Los tipos de datos más pequeños a menudo explotan las convenciones de llamadas modernas mejores, como el SysV ABI, que empaqueta datos de estructura de datos de manera eficiente en registros. Por ejemplo, puede devolver hasta una estructura de 16 bytes en los registros rdx:rax . Para una función que devuelve la estructura con 4 valores de uint32_t (inicializados desde una constante), eso se traduce en

    ret_constant32(): movabs rax, 8589934593 movabs rdx, 17179869187 ret

    La misma estructura con 4 uint_fast32_t 64 bits necesita un movimiento de registro y cuatro almacenes en la memoria para hacer lo mismo (y la persona que llama probablemente tendrá que leer los valores de la memoria después de la devolución):

    ret_constant64(): mov rax, rdi mov QWORD PTR [rdi], 1 mov QWORD PTR [rdi+8], 2 mov QWORD PTR [rdi+16], 3 mov QWORD PTR [rdi+24], 4 ret

    De manera similar, cuando se pasan argumentos de estructura, los valores de 32 bits se empaquetan aproximadamente el doble en los registros disponibles para los parámetros, por lo que es menos probable que se quede sin argumentos de registro y tenga que pasar a la pila 1 .

  • Incluso si elige usar uint_fast32_t para lugares donde "la velocidad importa", a menudo también tendrá lugares donde necesita un tipo de tamaño fijo. Por ejemplo, al pasar valores para salida externa, desde entrada externa, como parte de su ABI, como parte de una estructura que necesita un diseño específico, o porque usa de manera inteligente uint32_t para grandes agregaciones de valores para ahorrar en la huella de memoria. En los lugares donde sus uint_fast32_t y `` uint32_t` necesitan interconectarse, puede encontrar (además de la complejidad del desarrollo) extensiones de letrero innecesarias u otro código relacionado con la falta de coincidencia de tamaño. Los compiladores hacen un buen trabajo al optimizar esto en muchos casos, pero aún no es inusual ver esto en una salida optimizada cuando se mezclan tipos de diferentes tamaños.

Puedes jugar con algunos de los ejemplos anteriores y más sobre godbolt .

1 Para ser claros, la convención de empacar estructuras estrechamente en registros no siempre es una clara victoria para valores más pequeños. Sí significa que los valores más pequeños pueden tener que "extraerse" antes de que puedan usarse. Por ejemplo, una función simple que devuelve la suma de los dos miembros de la estructura juntos necesita un mov rax, rdi; shr rax, 32; add edi, eax mov rax, rdi; shr rax, 32; add edi, eax mov rax, rdi; shr rax, 32; add edi, eax mientras que para la versión de 64 bits cada argumento tiene su propio registro y solo necesita un solo add o lea . Sin embargo, si acepta que el diseño de "apretar las estructuras al pasar" tiene sentido en general, los valores más pequeños aprovecharán más esta característica.


Muchas rasones.

  1. Muchas personas no saben que existen los tipos ''rápidos''.
  2. Es más detallado escribir.
  3. Es más difícil razonar sobre el comportamiento de sus programas cuando no conoce el tamaño real del tipo.
  4. El estándar en realidad no es más rápido, ni puede realmente qué tipo es realmente más rápido puede ser muy dependiente del contexto.
  5. No he visto evidencia de que los desarrolladores de plataformas piensen en el tamaño de estos tipos al definir sus plataformas. Por ejemplo, en Linux x86-64, los tipos "rápidos" son todos de 64 bits, aunque x86-64 tiene soporte de hardware para operaciones rápidas en valores de 32 bits.

En resumen, los tipos "rápidos" son basura inútil. Si realmente necesita averiguar qué tipo es el más rápido para una aplicación determinada, debe comparar su código en su compilador.


No he visto evidencia de que uint32_t se use para su rango. En cambio, la mayoría de las veces que he visto que se usa uint32_t , es para contener exactamente 4 octetos de datos en varios algoritmos, ¡con semántica envolvente y de desplazamiento garantizada!

También hay otras razones para usar uint32_t lugar de uint_fast32_t : a menudo es que proporcionará ABI estable. Además, el uso de la memoria se puede conocer con precisión. Esto compensa en gran medida la ganancia de velocidad de uint_fast32_t , siempre que ese tipo sea distinto del de uint32_t .

Para valores <65536, ya hay un tipo útil, se llama unsigned int ( unsigned short debe tener al menos ese rango, pero unsigned int es del tamaño de la palabra nativa) Para valores <4294967296, hay otro llamado unsigned long .

Y, por último, la gente no usa uint_fast32_t porque es molestamente largo de escribir y fácil de escribir mal: D


Para fines prácticos, uint_fast32_t es completamente inútil. Está definido incorrectamente en la plataforma más extendida (x86_64), y realmente no ofrece ninguna ventaja en ningún lado a menos que tenga un compilador de muy baja calidad. Conceptualmente, nunca tiene sentido usar los tipos "rápidos" en las estructuras / matrices de datos: cualquier ahorro que obtenga del tipo que es más eficiente para operar se verá reducido por el costo (errores de caché, etc.) de aumentar el tamaño de Su conjunto de datos de trabajo. Y para variables locales individuales (contadores de bucles, temperaturas, etc.), un compilador que no sea de juguete generalmente puede funcionar con un tipo más grande en el código generado si eso es más eficiente, y solo truncarse al tamaño nominal cuando sea necesario para la corrección (y con tipos con signo, nunca es necesario).

La única variante que es teóricamente útil es uint_least32_t , para cuando necesita poder almacenar cualquier valor de 32 bits, pero quiere ser portátil para máquinas que carecen de un tipo de 32 bits de tamaño exacto. Prácticamente, hablando, sin embargo, eso no es algo de lo que deba preocuparse.


Se garantiza que uint32_t tiene casi las mismas propiedades en cualquier plataforma que lo admita. 1

uint_fast32_t tiene muy pocas garantías sobre cómo se comporta en diferentes sistemas en comparación.

Si cambia a una plataforma donde uint_fast32_t tiene un tamaño diferente, todo el código que usa uint_fast32_t debe uint_fast32_t a uint_fast32_t y validarse. Todos los supuestos de estabilidad van a estar fuera de la ventana. Todo el sistema funcionará de manera diferente.

Al escribir su código, es posible que ni siquiera tenga acceso a un sistema uint_fast32_t que no tenga un tamaño de 32 bits.

uint32_t no funcionará de manera diferente (ver nota al pie).

La corrección es más importante que la velocidad. La corrección prematura es, por lo tanto, un mejor plan que la optimización prematura.

En el caso de que estuviera escribiendo código para sistemas donde uint_fast32_t tenía 64 o más bits, podría probar mi código para ambos casos y usarlo. Salvo la necesidad y la oportunidad, hacerlo es un mal plan.

Finalmente, uint_fast32_t cuando lo está almacenando por cualquier período de tiempo o número de instancias puede ser más lento que uint32 simplemente debido a problemas de tamaño de caché y ancho de banda de memoria. Las computadoras de hoy en día están mucho más vinculadas a la memoria que a la CPU, y uint_fast32_t podría ser más rápido de forma aislada, pero no después de tener en cuenta la sobrecarga de memoria.

1 Como @chux ha señalado en un comentario, si unsigned es mayor que uint32_t , la aritmética en uint32_t pasa por las promociones enteras habituales, y si no, permanece como uint32_t . Esto puede causar errores. Nada es perfecto


Según tengo entendido, inicialmente se suponía que int era un tipo entero "nativo" con garantía adicional de que debería tener al menos 16 bits de tamaño, algo que se consideraba tamaño "razonable" en ese momento.

Cuando las plataformas de 32 bits se hicieron más comunes, podemos decir que el tamaño "razonable" ha cambiado a 32 bits:

  • Windows moderno usa int 32 bits en todas las plataformas.
  • POSIX garantiza que int es de al menos 32 bits.
  • C #, Java tiene un tipo int que garantiza exactamente 32 bits.

Pero cuando la plataforma de 64 bits se convirtió en la norma, nadie expandió int para ser un entero de 64 bits debido a:

  • Portabilidad: una gran cantidad de código depende de que int tenga un tamaño de 32 bits.
  • Consumo de memoria: duplicar el uso de memoria para cada int puede no ser razonable en la mayoría de los casos, ya que en la mayoría de los casos los números en uso son mucho más pequeños que 2 mil millones.

Ahora, ¿por qué preferirías uint32_t a uint_fast32_t ? Por la misma razón, los lenguajes, C # y Java siempre usan enteros de tamaño fijo: el programador no escribe código pensando en posibles tamaños de diferentes tipos, escribe para una plataforma y prueba el código en esa plataforma. La mayor parte del código depende implícitamente de tamaños específicos de tipos de datos. Y esta es la razón por la cual uint32_t es una mejor opción para la mayoría de los casos: no permite ninguna ambigüedad con respecto a su comportamiento.

Además, ¿es uint_fast32_t realmente el tipo más rápido en una plataforma con un tamaño igual o mayor a 32 bits? Realmente no. Considere este compilador de código de GCC para x86_64 en Windows:

extern uint64_t get(void); uint64_t sum(uint64_t value) { return value + get(); }

El ensamblaje generado se ve así:

push %rbx sub $0x20,%rsp mov %rcx,%rbx callq d <sum+0xd> add %rbx,%rax add $0x20,%rsp pop %rbx retq

Ahora, si cambia get() el valor de retorno de uint_fast32_t (a 4 bytes en Windows x86_64) obtendrá esto:

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

Observe cómo el código generado es casi el mismo, excepto para la mov %eax,%eax instrucción adicional después de la llamada a la función, que pretende expandir el valor de 32 bits a un valor de 64 bits.

No existe tal problema si solo usa valores de 32 bits, pero probablemente usará aquellos con size_t variables (¿tamaños de matriz probablemente?) Y esos son 64 bits en x86_64. En Linux uint_fast32_t es de 8 bytes, por lo que la situación es diferente.

Muchos programadores usan int cuando necesitan devolver un valor pequeño (digamos en el rango [-32,32]). Esto funcionaría perfectamente si int se tratara de plataformas de tamaño entero nativo, pero dado que no está en plataformas de 64 bits, otro tipo que coincida con el tipo nativo de plataforma es una mejor opción (a menos que se use con frecuencia con otros enteros de menor tamaño).

Básicamente, independientemente de lo que diga el estándar, de uint_fast32_t todas formas se rompe en algunas implementaciones. Si le interesan las instrucciones adicionales generadas en algunos lugares, debe definir su propio tipo de entero "nativo". O puede usar size_t para este propósito, ya que generalmente coincidirá con el native tamaño (no incluyo plataformas viejas y oscuras como 8086, solo plataformas que pueden ejecutar Windows, Linux, etc.).

Otra señal que se muestra que int se supone que es un tipo entero nativo es "regla de promoción de enteros". La mayoría de las CPU solo pueden realizar operaciones en nativo, por lo que la CPU de 32 bits generalmente solo puede hacer sumas, restas, etc. de 32 bits (las CPU Intel son una excepción aquí). Los tipos enteros de otros tamaños solo son compatibles con las instrucciones de carga y almacenamiento. Por ejemplo, el valor de 8 bits debe cargarse con las instrucciones apropiadas "cargar con 8 bits con signo" o "cargar con 8 bits sin signo" y expandirá el valor a 32 bits después de la carga. Sin la regla de promoción de enteros, los compiladores de C tendrían que agregar un poco más de código para las expresiones que usan tipos más pequeños que los nativos. Desafortunadamente, esto ya no se cumple con las arquitecturas de 64 bits, ya que los compiladores ahora tienen que emitir instrucciones adicionales en algunos casos (como se mostró anteriormente).


Una razón es que unsigned int ya es "más rápido" sin la necesidad de ningún tipo de definición especial o la necesidad de incluir algo. Entonces, si lo necesita rápido, simplemente use el tipo int fundamental o unsigned int .
Si bien el estándar no garantiza explícitamente que sea el más rápido, indirectamente lo hace al afirmar que "los planos tienen el tamaño natural sugerido por la arquitectura del entorno de ejecución" en 3.9.1. En otras palabras, int (o su contraparte sin signo) es con lo que el procesador se siente más cómodo.

Ahora, por supuesto, no sabes de qué tamaño podría ser unsigned int . Solo sabe que es al menos tan grande como short (y parece recordar que short debe tener al menos 16 bits, ¡aunque no puedo encontrarlo en el estándar ahora!). Por lo general, es simplemente simple de 4 bytes, pero en teoría podría ser más grande, o en casos extremos, incluso más pequeño ( aunque personalmente nunca he encontrado una arquitectura donde este fuera el caso, ni siquiera en computadoras de 8 bits en la década de 1980. .. tal vez algunos microcontroladores, quién sabe resulta que sufro de demencia, int era claramente 16 bits en ese entonces).

El estándar C ++ no se molesta en especificar cuáles son los tipos <cstdint> o qué garantizan, simplemente menciona "igual que en C".

uint32_t , según el estándar C, garantiza que obtenga exactamente 32 bits. No hay nada diferente, nada menos y sin partes de relleno. A veces esto es exactamente lo que necesita y, por lo tanto, es muy valioso.

uint_least32_t garantiza que cualquiera que sea el tamaño, no puede ser menor que 32 bits (pero podría muy bien ser mayor). A veces, pero mucho más raramente que un witdh exacto o "no me importa", esto es lo que quieres.

Por último, uint_fast32_t es algo superfluo en mi opinión, excepto para fines de documentación de intenciones. El estándar C establece "designa un tipo entero que generalmente es el más rápido" (tenga en cuenta la palabra "generalmente") y menciona explícitamente que no necesita ser más rápido para todos los propósitos. En otras palabras, uint_fast32_t es casi lo mismo que uint_least32_t , que generalmente también es el más rápido, solo que no se ofrece ninguna garantía (pero no hay garantía de ninguna manera).

Como la mayoría de las veces no le importa el tamaño exacto o desea exactamente 32 (o 64, a veces 16) bits, y dado que el tipo unsigned int "no importa" es más rápido de todos modos, esto explica por qué uint_fast32_t No se usa con tanta frecuencia.