long float estandar bytes c int c99 portability c89

float - ¿Cuál es la diferencia entre "int" e "int_fast16_t"?



unsigned long c (7)

Según lo entiendo, la especificación C dice que se supone que tipo int es el tipo más eficiente en la plataforma de destino que contiene al menos 16 bits.

Esto es lo que realmente dice la norma sobre int : ( N1570 draft , sección 6.2.5, párrafo 5):

Un objeto int "simple" tiene el tamaño natural sugerido por la arquitectura del entorno de ejecución (lo suficientemente grande como para contener cualquier valor en el rango INT_MIN a INT_MAX como se define en el encabezado <limits.h> ).

La referencia a INT_MIN e INT_MAX es quizás ligeramente engañosa; esos valores se eligen en función de las características de tipo int , y no al revés.

Y la frase " el tamaño natural" también es ligeramente engañosa. Dependiendo de la arquitectura del objetivo, puede que no haya solo un tamaño "natural" para un tipo entero.

En otro lugar, el estándar dice que INT_MIN debe ser como máximo -32767 , e INT_MAX debe ser al menos +32767 , lo que implica que int es de al menos 16 bits.

int_fast16_t es lo que dice el estándar sobre int_fast16_t (7.20.1.3):

Cada uno de los siguientes tipos designa un tipo de entero que suele ser el más rápido para operar entre todos los tipos de enteros que tienen al menos el ancho especificado.

con una nota al pie:

No se garantiza que el tipo designado sea el más rápido para todos los propósitos; si la implementación no tiene bases claras para elegir un tipo sobre otro, simplemente seleccionará un tipo de entero que satisfaga los requisitos de signatura y ancho.

Los requisitos para int e int_fast16_t son similares pero no idénticos, y son igualmente vagos.

En la práctica, el tamaño de int menudo se elige según criterios distintos de "el tamaño natural", o esa frase se interpreta por conveniencia. A menudo, el tamaño de int para una nueva arquitectura se elige para que coincida con el tamaño de una arquitectura existente, para minimizar la dificultad de portar el código. Y hay una motivación bastante fuerte para hacer que int no sea más ancho que 32 bits, de modo que los tipos char , short e int pueden cubrir tamaños de 8, 16 y 32 bits. En los sistemas de 64 bits, particularmente x86-64, el tamaño "natural" probablemente sea de 64 bits, pero la mayoría de los compiladores de C crean int 32 bits en lugar de 64 (y algunos compiladores incluso hacen long solo 32 bits).

La elección del tipo subyacente para int_fast16_t es, sospecho, menos dependiente de tales consideraciones, ya que cualquier código que lo use solicita explícitamente un tipo entero de 16 bits con signo rápido. Una gran cantidad de código existente hace suposiciones sobre las características de int que van más allá de lo que las garantías estándar, y los desarrolladores de compiladores tienen que atender a dicho código si quieren que se utilicen sus compiladores.

Según lo entiendo, la especificación C dice que se supone que tipo int es el tipo más eficiente en la plataforma de destino que contiene al menos 16 bits.

¿No es exactamente eso lo que la definición C99 de int_fast16_t es también?

Tal vez lo ponen allí solo por coherencia, ya que los otros int_fastXX_t son necesarios?

Actualizar

Para resumir la discusión a continuación:

  • Mi pregunta era incorrecta de muchas maneras. El estándar C no especifica bitness para int . Da un rango [-32767,32767] que debe contener.
  • Me doy cuenta al principio que la mayoría de la gente diría, "¡pero ese rango implica al menos 16 bits!" Pero C no requiere el almacenamiento de dos enteros (o incluso binario) de enteros. Si hubieran dicho "16 bits", puede haber algunas plataformas que tengan una paridad de 1 bit, una señal de 1 bit y una magnitud de 14 bits que aún estén "cumpliendo el estándar", pero que no satisfagan ese rango.
  • El estándar no dice nada sobre int siendo el tipo más eficiente. Además de los requisitos de tamaño anteriores, int puede decidirse por el desarrollador del compilador según los criterios que considere más importantes. (velocidad, tamaño, compatibilidad con versiones anteriores, etc.)
  • Por otro lado, int_fast16_t es como proporcionar una pista al compilador de que debe usar un tipo que sea óptimo para el rendimiento, posiblemente a expensas de cualquier otra compensación.
  • Del mismo modo, int_least16_t le diría al compilador que use el tipo más pequeño que sea> = 16 bits, incluso si fuera más lento. Bueno para preservar el espacio en arreglos grandes y esas cosas.

Ejemplo: MSVC en x86-64 tiene un int de 32 bits, incluso en sistemas de 64 bits. MS optó por hacer esto porque demasiadas personas suponían que int siempre sería exactamente de 32 bits, por lo que se romperían muchos ABI. Sin embargo, es posible que int_fast32_t sea ​​un número de 64 bits si los valores de 64 bits fueran más rápidos en x86-64. (Lo cual no creo que sea realmente el caso, pero solo demuestra el punto)


De la lógica de C99 7.8 Formato de conversión de tipos enteros <inttypes.h> (documento que acompaña a Standard), énfasis mío:

C89 especifica que el lenguaje debe admitir cuatro tipos de datos enteros con signo y sin signo, char , short , int y long , pero establece muy poco requisito en su tamaño que no sea int y short sea ​​al menos de 16 bits y long sea ​​al menos tan largo como int y no más pequeño que 32 bits . Para sistemas de 16 bits, la mayoría de las implementaciones asignan 8, 16, 16 y 32 bits a char , short , int y long , respectivamente. Para sistemas de 32 bits, la práctica común es asignar 8, 16, 32 y 32 bits a estos tipos. Esta diferencia en el tamaño int puede crear algunos problemas para los usuarios que migran de un sistema a otro que asigna diferentes tamaños a tipos enteros, porque la regla de promoción de entero C estándar puede producir cambios silenciosos inesperadamente. La necesidad de definir un tipo de entero extendido aumentó con la introducción de sistemas de 64 bits.

El objetivo de <inttypes.h> es proporcionar un conjunto de tipos enteros cuyas definiciones sean consistentes en todas las máquinas e independientes de los sistemas operativos y otras idiosincrasias de implementación . Define, a través de typedef , tipos enteros de varios tamaños. Las implementaciones son libres de typedef como tipos de entero C estándar o extensiones que admiten. El uso constante de este encabezado aumentará en gran medida la portabilidad del programa de un usuario en todas las plataformas.

La principal diferencia entre int e int_fast16_t es que este último es probable que esté libre de estas "idiosincrasias de implementación". Puede pensar en algo así como:

No me importa la actual "política" de OS / implementación de tamaño int . Solo dame el tipo de entero con signo más rápido con al menos 16 bits.


En algunas plataformas, usar valores de 16 bits puede ser mucho más lento que usar valores de 32 bits [por ejemplo, una tienda de 8 bits o 16 bits requeriría realizar una carga de 32 bits, modificar el valor cargado y escribir el resultado] . Incluso si uno pudiera caber el doble de valores de 16 bits en una caché que los valores de 32 bits (la situación normal donde los valores de 16 bits serían más rápidos que los valores de 32 bits en sistemas de 32 bits), la necesidad de tener cada escritura precedido por una lectura negaría cualquier ventaja de velocidad que pudiera producirse a menos que se leyera una estructura de datos mucho más a menudo de lo que se escribió. En tales plataformas, un tipo como int_fast16_t probablemente sea de 32 bits.

Habiendo dicho eso, el Estándar no desafortunadamente permite cuál sería la semántica más útil para un compilador, que sería permitir que las variables de tipo int_fast16_t cuya dirección no se tome se comporten arbitrariamente como tipos de 16 bits o tipos más grandes, dependiendo de lo que es conveniente Considere, por ejemplo, el método:

int32_t blah(int32_t x) { int_fast16_t y = x; return y; }

En muchas plataformas, los enteros de 16 bits almacenados en la memoria a menudo se pueden manipular igual que los almacenados en los registros, pero no hay instrucciones para realizar operaciones de 16 bits en los registros. Si una variable int_fast16_t almacenada en la memoria solo puede contener -32768 a +32767, esa misma restricción se aplicaría a int_fast16_t variables int_fast16_t almacenadas en los registros. Como forzar valores sobredimensionados en tipos enteros con signo demasiado pequeños para mantenerlos es un comportamiento definido por la implementación, que obligaría al código anterior a agregar instrucciones para extender signos los 16 bits inferiores de x antes de devolverlos; si el estándar permitiera tal tipo, un tipo flexible de "al menos 16 bits, pero más si es conveniente" podría eliminar la necesidad de tales instrucciones.


La diferencia es que se permite que los tipos rápidos sean más anchos que sus contrapartes (sin rapidez ) con fines de eficiencia / optimización. Pero el estándar C de ninguna manera garantiza que sean realmente más rápidos.

C11, 7.20.1.3 Tipos enteros de ancho mínimo más rápidos

1 Cada uno de los siguientes tipos designa un tipo de entero que generalmente es más rápido 262) para operar con todos los tipos de enteros que tienen al menos el ancho especificado.

2 El nombre de typedef int_fastN_t designa el tipo de entero con signo más rápido con un ancho de al menos N. El nombre de typedef uint_fastN_t designa el tipo entero sin signo más rápido con un ancho de al menos N.

262) No se garantiza que el tipo designado sea el más rápido para todos los propósitos; si la implementación no tiene bases claras para elegir un tipo sobre otro, simplemente seleccionará un tipo de entero que satisfaga los requisitos de signatura y ancho.

Otra diferencia es que los tipos rápidos y menos son tipos requeridos, mientras que otros tipos de ancho exacto son opcionales :

3 Se requieren los siguientes tipos: int_fast8_t int_fast16_t int_fast32_t int_fast64_t uint_fast8_t uint_fast16_t uint_fast32_t uint_fast64_t Todos los demás tipos de este formulario son opcionales.


Un ejemplo de cómo los dos tipos pueden ser diferentes: supongamos que hay una arquitectura en la que la aritmética de 8 bits, 16 bits, 32 bits y 64 bits es igualmente rápida. (El i386 se acerca). Entonces, el implementador podría usar un modelo LLP64, o mejor aún, permitir que el programador elija entre ILP64, LP64 y LLP64, ya que hay una gran cantidad de código que supone que mucho es exactamente 32 bits, y eso sizeof(int) <= sizeof(void*) <= sizeof(long) . Cualquier implementación de 64 bits debe violar al menos una de estas suposiciones.

En ese caso, int probablemente tenga 32 bits de ancho, porque eso romperá el menor código de otros sistemas, pero uint_fast16_t aún podría tener 16 bits de ancho, ahorrando espacio.


int es un "tipo más eficiente" en velocidad / tamaño, pero eso no está especificado por la especificación C. Debe ser de 16 o más bits.

int_fast16_t es el tipo de velocidad más eficiente con al menos el rango de 16 bit int.

Ejemplo: una plataforma determinada puede haber decidido que int debe ser de 32 bits por muchas razones, no solo por la velocidad. El mismo sistema puede encontrar que un tipo diferente es más rápido para enteros de 16 bits.

Ejemplo: en una máquina de 64 bits, donde uno esperaría tener int como 64 bits, un compilador puede usar un modo con compilación int 32 bits para la compatibilidad. En este modo, int_fast16_t podría ser de 64 bits, ya que es el ancho más rápido de forma nativa, ya que evita problemas de alineación, etc.


int_fast16_t garantiza ser el int más rápido con un tamaño de al menos 16 bits. int no tiene garantía de su tamaño excepto que:

sizeof(char) = 1 and sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long).

Y que puede mantener el rango de -32767 a +32767.

(7.20.1.3p2) "El nombre de typedef int_fastN_t designa el tipo de entero con signo más rápido con un ancho de al menos N. El nombre typedef uint_fastN_t designa el tipo entero sin signo más rápido con un ancho de al menos N ".