C99 (anteriormente conocido como C9X ) es un nombre informal para ISO/IEC 9899:1999 , una versión anterior del estándar del lenguaje de programación C. [1] Amplía la versión anterior ( C90 ) con nuevas características para el lenguaje y la biblioteca estándar , y ayuda a las implementaciones a hacer un mejor uso del hardware informático disponible, como la aritmética de punto flotante IEEE 754-1985 y la tecnología de compilación. [2] La versión C11 del estándar del lenguaje de programación C, publicada en 2011, actualiza C99.
Después de que ANSI produjera el estándar oficial para el lenguaje de programación C en 1989, que se convirtió en un estándar internacional en 1990, la especificación del lenguaje C permaneció relativamente estática durante algún tiempo, mientras que C++ continuó evolucionando, en gran medida durante su propio esfuerzo de estandarización. La Enmienda Normativa 1 creó un nuevo estándar para C en 1995, pero sólo para corregir algunos detalles del estándar de 1989 y agregar un soporte más extenso para juegos de caracteres internacionales. La norma se sometió a nuevas revisiones a finales de la década de 1990, lo que llevó a la publicación de ISO/IEC 9899:1999 en 1999, que fue adoptada como norma ANSI en mayo de 2000. El lenguaje definido por esa versión de la norma se conoce comúnmente como " C99". El estándar internacional C es mantenido por el grupo de trabajo ISO/IEC JTC1/SC22 /WG14.
C99 es, en su mayor parte, compatible con versiones anteriores de C89, pero es más estricto en algunos aspectos. [3]
En particular, una declaración que carece de un especificador de tipo ya no se int
asume implícitamente. El comité de estándares de C decidió que era más valioso para los compiladores diagnosticar la omisión involuntaria del especificador de tipo que procesar silenciosamente código heredado que dependía de implícitos int
. En la práctica, es probable que los compiladores muestren una advertencia y luego asuman int
y continúen traduciendo el programa.
C99 introdujo varias características nuevas, muchas de las cuales ya se habían implementado como extensiones en varios compiladores: [4]
long long int
tipos enteros extendidos opcionales, un tipo de datos booleano explícito y un complex
tipo para representar números complejos.//
, como en BCPL , C++ y Javasnprintf
<stdbool.h>
<complex.h>
<tgmath.h>
<inttypes.h>
<tgmath.h>
, que seleccionan una función de biblioteca matemática basada en , o argumentos, etc.float
double
long double
struct point p = { .x = 1, .y = 2 };
[ 5]function((struct x) {1, 2})
[ 6]restrict
La calificación permite una optimización del código más agresiva , eliminando las ventajas de acceso a matrices en tiempo de compilación que anteriormente tenía FORTRAN sobre ANSI C [7]\u0040
secuencias hexadecimales de cuatro u ocho dígitos\U0001f431
static
en índices de matriz en declaraciones de parámetros [8]Partes del estándar C99 están incluidas en la versión actual del estándar C++ , incluidos tipos de enteros, encabezados y funciones de biblioteca. Las matrices de longitud variable no se encuentran entre estas partes incluidas porque la biblioteca de plantillas estándar de C++ ya incluye una funcionalidad similar.
Una característica importante de C99 es su soporte numérico y, en particular, su soporte para acceder a las características del hardware de punto flotante IEEE 754-1985 (también conocido como IEC 60559) presente en la gran mayoría de los procesadores modernos (definido en el "Anexo F IEC 60559 aritmética de punto flotante"). Las plataformas sin hardware IEEE 754 también pueden implementarlo en software. [2]
En plataformas con punto flotante IEEE 754:
float
se define como precisión simple IEEE 754 , double
se define como precisión doble y se define como precisión extendidalong double
IEEE 754 (por ejemplo, doble precisión extendida Intel de 80 bits en plataformas x86 o x86-64 ), o alguna forma de precisión cuádruple cuando esté disponible; de lo contrario, es doble precisión.FLT_EVAL_METHOD == 2
indica que todos los cálculos intermedios internos se realizan de forma predeterminada con alta precisión (doble largo) cuando esté disponible (por ejemplo, doble extendido de 80 bits ), FLT_EVAL_METHOD == 1
realiza todas las expresiones intermedias internas con doble precisión (a menos que un operando sea doble largo), mientras FLT_EVAL_METHOD == 0
especifica que cada operación se evalúa solo con la precisión del operando más amplio de cada operador. El tipo de resultado intermedio para operandos de una precisión determinada se resume en la tabla adyacente.FLT_EVAL_METHOD == 2
tiende a limitar el riesgo de errores de redondeo que afectan a expresiones numéricamente inestables (consulte la justificación del diseño IEEE 754 ) y es el método predeterminado diseñado para hardware x87 , pero produce un comportamiento poco intuitivo para el usuario desprevenido; [9] FLT_EVAL_METHOD == 1
era el método de evaluación predeterminado utilizado originalmente en K&R C , que promovía que todos los flotantes se duplicaran en las expresiones; y FLT_EVAL_METHOD == 0
también se usa comúnmente y especifica una estricta "evaluación del tipo" de los operandos. (Para gcc , FLT_EVAL_METHOD == 2
es el valor predeterminado en x86 de 32 bits y FLT_EVAL_METHOD == 0
es el predeterminado en x86-64 de 64 bits, pero FLT_EVAL_METHOD == 2
se puede especificar en x86-64 con la opción -mfpmath=387). Antes de C99, los compiladores podían redondear los resultados intermedios de manera inconsistente, especialmente cuando se utiliza hardware de punto flotante x87 , lo que genera un comportamiento específico del compilador; [10] tales inconsistencias no están permitidas en los compiladores conformes al C99 (anexo F).
El siguiente ejemplo de código C99 anotado para calcular una función de fracción continua demuestra las características principales:
#incluir <stdio.h> #incluir <matemáticas.h> #incluir <flotador.h> #incluir <fenv.h> #incluir <tgmath.h> #incluir <stdbool.h> #incluir <afirmar.h> doble cálculo_fn ( doble z ) // [1] { #pragma STDC FENV_ACCESS ON // [2] afirmar ( FLT_EVAL_METHOD == 2 ); // [3] si ( isnan ( z )) // [4] pone ( "z no es un número" ); si ( isinf ( z )) pone ( "z es infinita" ); doble largo r = 7,0 - 3,0 / ( z - 2,0 - 1,0 / ( z - 7,0 + 10,0 / ( z - 2,0 - 2,0 / ( z - 3,0 )))); // [5, 6] feclearexcept ( FE_DIVBYZERO ); // [7] bool elevado = fetestexcept ( FE_OVERFLOW ); // [8] si ( levantado ) puts ( "Desbordamiento inesperado." ); devolver r ; }int principal ( vacío ) { #ifndef __STDC_IEC_559__ puts ( "Advertencia: __STDC_IEC_559__ no definido. El punto flotante IEEE 754 no es totalmente compatible." ); // [9] #terminara si #pragma STDC FENV_ACCESS ACTIVADO #ifdef TEST_NUMERIC_STABILITY_UP fesetround ( FE_UPWARD ); // [10] #elif TEST_NUMERIC_STABILITY_DOWN fesetround ( FE_DOWNWARD ); #terminara si printf ( "%.7g \n " , Compute_fn ( 3.0 )); printf ( "%.7g \n " , cálculo_fn ( NAN )); devolver 0 ; }
Notas a pie de página:
gcc -std=c99 -mfpmath=387 -o test_c99_fp test_c99_fp.c -lm
STDC
están definidos en el estándar C).long double
se define como IEEE 754 de doble extensión o precisión cuádruple, si está disponible. El uso de una precisión mayor que la requerida para los cálculos intermedios puede minimizar el error de redondeo [11] (el typedef double_t
se puede usar para código que es portátil en todos FLT_EVAL_METHOD
los s).FLT_EVAL_METHOD
se define como 2, todos los cálculos internos, incluidas las constantes, se realizarán con doble precisión larga; si FLT_EVAL_METHOD
se define como 0, se necesita cuidado adicional para garantizar esto, incluidas posiblemente conversiones adicionales y una especificación explícita de constantes como doble larga).__STDC_IEC_559__
se definirá sólo si el compilador y la biblioteca C implementan completamente la "aritmética de punto flotante IEC 60559 del Anexo F" (los usuarios deben tener en cuenta que esta macro a veces se define cuando no debería).TEST_NUMERIC_STABILITY_UP
etc. en este ejemplo, durante la depuración) para diagnosticar la inestabilidad numérica. [12] Este método se puede utilizar incluso si compute_fn()
forma parte de una biblioteca binaria compilada por separado. Pero dependiendo de la función, no siempre es posible detectar inestabilidades numéricas.__STDC_VERSION__
Se define una macro estándar con un valor 199901L
para indicar que la compatibilidad con C99 está disponible. Al igual que con la __STDC__
macro para C90, __STDC_VERSION__
se puede usar para escribir código que se compilará de manera diferente para los compiladores C90 y C99, como en este ejemplo que garantiza que inline
esté disponible en cualquier caso (reemplazándolo con static
C90 para evitar errores del vinculador).
#if __STDC_VERSION__ >= 199901L /* "inline" es una palabra clave */ #else # define inline static #endif
La mayoría de los compiladores de C brindan soporte para al menos algunas de las características introducidas en C99.
Históricamente, Microsoft ha tardado en implementar nuevas funciones de C en sus herramientas de Visual C++ , centrándose principalmente en respaldar los desarrollos en los estándares de C++. [13] Sin embargo, con la introducción de Visual C++ 2013, Microsoft implementó un subconjunto limitado de C99, que se amplió en Visual C++ 2015. [14]
Desde la ratificación del estándar C de 1999, el grupo de trabajo de estándares preparó informes técnicos que especifican un soporte mejorado para el procesamiento integrado, tipos de datos de caracteres adicionales ( soporte Unicode ) y funciones de biblioteca con verificación de límites mejorada . Continúa el trabajo en informes técnicos que abordan el punto flotante decimal, funciones matemáticas especiales adicionales y funciones adicionales de asignación de memoria dinámica . Los comités de estándares C y C++ han estado colaborando en especificaciones para programación con subprocesos .
La siguiente revisión del estándar C, C11 , fue ratificada en 2011. [41] El comité de estándares C adoptó directrices que limitaban la adopción de nuevas características que no han sido probadas por implementaciones existentes. Se dedicó mucho esfuerzo a desarrollar un modelo de memoria para aclarar los puntos de secuencia y soportar la programación por subprocesos .