C99 (Estándar de C)
C99 (formalmente conocido como ISO/IEC 9899:1999 ) es una revisión del estándar abierto para lenguaje de programación C. [1] Sucede a la versión anterios (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 del compilador. [2] Fue sustituida por la revisión C11, publicada en 2011.

Predecesor: ANSI C |
Estándares de C |
Sucesor: C11 |
Historia
editarDespués de que ANSI desarrollara 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 cierto tiempo. Mientras tanto, C++ continuó evolucionando, en gran medida por 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 para agregar soporte más amplio para conjuntos de caracteres internacionales. La norma fue objeto de una revisión adicional 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 del estándar se conoce comúnmente como "C99". El estándar internacional C es mantenido por el grupo de trabajo ISO/IEC JTC1/SC22 /WG14.
Diseño
editarC99 es, en gran parte, compatible con C89, pero es más estricto en algunos aspectos. [3]
En concreto, una declaración que carece de un especificador de tipo ya no se asume implícitamente de tipo int
. El comité de estándares C decidió que era más valioso para los compiladores diagnosticar la omisión del especificador de tipo que procesar silenciosamente el código heredado que dependía de la asunción implicita del tipo int
. En la práctica, es probable que los compiladores muestren una advertencia, y luego asuman el tipo int
y continúen traduciendo el programa.
C99 introdujo varias características nuevas, muchas de las cuales ya habían sido implementadas como extensiones en varios compiladores: [4]
- funciones en línea (inline)
- Declaraciones y código entremezclados: la declaración de variables ya no está restringida al alcance del archivo o al inicio de una declaración compuesta (bloque)
- Varios tipos de datos nuevos, incluidos
long long int
, tipos de enteros extendidos opcionales, un tipo de datos booleano explícito y un tipocomplex
para representar números complejos. - Arrays de longitud variable (VLA) (aunque posteriormente relegadas en C11 a una característica condicional que las implementaciones no están obligadas a soportar)
- miembros de array flexibles
- Soporte para comentarios de una línea que comiencen con
//
, como en BCPL, C++ y Java - Nuevas funciones de biblioteca, como
snprintf
- Nuevos encabezados, como
<stdbool.h>
,<complex.h>
,<tgmath.h>
y<inttypes.h>
- funciones matemáticas (macros) de tipo genérico, en
<tgmath.h>
, que seleccionan una función de biblioteca matemática en función de argumentosfloat
,double
olong double
, etc. - Soporte mejorado para arithmética de punto flotante IEEE
- Inicializadores designados (por ejemplo, inicializar una estructura por nombres de campo:
struct point p = { .x = 1, .y = 2 };
) [5] - Literales compuestos ("compund literals") (por ejemplo, es posible construir estructuras en llamadas de función:
function((struct x) {1, 2})
) [6] - Soporte para macros variádicas (macros con un número variable de argumentos)
- La calificación
restrict
permite una optimización de código más agresiva, eliminando las ventajas de acceso a array en tiempo de compilación que anteriormente tenía FORTRAN sobre ANSI C [7] - Nombres de caracteres universales, que permiten que las variables de usuario contengan caracteres distintos del conjunto de caracteres estándar: secuencias hexadecimales
\u0040
de cuatro dígitos o\U0001f431
de ocho dígitos - Palabra clave
static
en índices de array en declaraciones de parámetros [8]
Partes del estándar C99 están incluidas en la versión actual del estándar C++, incluidos los tipos enteros, encabezados y funciones de biblioteca. Los arrays de longitud variable no se encuentran entre estas partes incluidas porque la biblioteca de plantillas estándar de C++ ya incluye una funcionalidad similar.
Soporte de punto flotante IEEE 754
editarUna característica importante de C99 es su soporte numérico y, en particular, su soporte para el acceso a las características de IEEE 754-1985 (también conocido como IEC 60559) hardware de punto flotante presente en la gran mayoría de procesadores modernos (definido en el "Anexo F IEC 60559 aritmética de punto flotante"). Plataformas sin soporte hardware para IEEE 754 también pueden implementarlo en software. [2]
En plataformas con soporte para aritmética de punto flotante IEEE 754:
float
es definido como un real de precisión simple IEEE 754,double
es definido como un real de precisión doble IEEE 754 ylong double
es definido como un real de precisión extendida IEEE 754 (p.e. Intel 80-bit double de precisión extendida en plataformas x86 o x86-64), u otras formas de precisión cuádruple, cuando estén disponibles- Los 4 operadores aritméticos, y la raíz cuadrada, son redondeados según el estándar IEEE 754
- La evaluación de expresiones se define para ser realizada en una de las 3 maneras existentes, indicando
- La evaluación de expresiones se define para realizarse en uno de los tres métodos bien definidos, que indican si las variables de punto flotante se promueven primero a un formato más preciso en las expresiones
- FLT_EVAL_METHOD == 2 indica que todos los cálculos intermedios internos se realizan de forma predeterminada con alta precisión (doble largo) donde esté disponible (por ejemplo, 80 bit doble extendido)
- FLT_EVAL_METHOD == 1 realiza todas las expresiones intermedias internas con doble precisión (a menos que un operando sea long double)
- FLT_EVAL_METHOD == 0 especifica que cada operación se evalúa solo con la precisión del operando más ancho de cada operador. El tipo de resultado intermedio para los operandos de una precisión dada se resume en la siguiente tabla:
FLT_EVAL_METHOD
|
float
|
double
|
long double
|
---|---|---|---|
0
|
float
|
double
|
long double
|
1
|
double
|
double
|
long double
|
2
|
long double
|
long double
|
long double
|
El método FLT_EVAL_METHOD == 2
tiende a limitar el riesgo de errores de redondeo que afectan a expresiones numéricamente inestables (ver IEEE 754 fundamento del diseño ) y es el método predeterminado diseñado para hardware x87, pero tiene un comportamiento poco intuitivo para el usuario incauto; [9] FLT_EVAL_METHOD == 1
fue el método de evaluación predeterminado utilizado originalmente en K&R C, que promovía todos los float
a double
en las expresiones; y FLT_EVAL_METHOD == 0
también se usa comúnmente y especifica una estricta "evaluación al tipo" de los operandos. (Para gcc, FLT_EVAL_METHOD == 2
es el valor predeterminado en 32 bit x86 y FLT_EVAL_METHOD == 0
es el valor predeterminado en 64 bit x86-64, pero FLT_EVAL_METHOD == 2
(Se puede especificar FLT_EVAL_METHOD == 2
en x86-64 con la opción -mfpmath=387.) Antes de C99, los compiladores podían redondear los resultados intermedios de manera inconsistente, especialmente al usar hardware de punto flotante x87, lo que generaba un comportamiento específico del compilador; [10] dichas inconsistencias no están permitidas en compiladores que cumplen con C99 (anexo F).
Ejemplo
editarEl siguiente ejemplo de código C99 anotado para calcular una función de fracción continua demuestra las características principales:
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.h>
#include <tgmath.h>
#include <stdbool.h>
#include <assert.h>
double compute_fn(double z) // [1]
{
#pragma STDC FENV_ACCESS ON // [2]
assert(FLT_EVAL_METHOD == 2); // [3]
if (isnan(z)) // [4]
puts("z no es un número");
if (isinf(z))
puts("z es infinito");
long double 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 raised = fetestexcept(FE_OVERFLOW); // [8]
if (raised)
puts("Desbordamiento no anticipado.");
return r;
}
int main(void)
{
#ifndef __STDC_IEC_559__
puts("Warning: __STDC_IEC_559__ no definido. Aritmética de punto flotante IEEE 754 no soportada."); // [9]
#endif
#pragma STDC FENV_ACCESS ON
#ifdef TEST_NUMERIC_STABILITY_UP
fesetround(FE_UPWARD); // [10]
#elif TEST_NUMERIC_STABILITY_DOWN
fesetround(FE_DOWNWARD);
#endif
printf("%.7g\n", compute_fn(3.0));
printf("%.7g\n", compute_fn(NAN));
return 0;
}
Notas al pie:
- Compilar con:
gcc -std=c99 -mfpmath=387 -o test_c99_fp test_c99_fp.c -lm
- Como indica el IEEE 754, en esta función se manipulan indicadores de estado; este #pragma es necesario para evitar que el compilador reorganice incorrectamente dichas pruebas al optimizar. (Los pragmas generalmente están definidos por la implementación, pero aquellos con el prefijo
STDC
están definidos en el estándar C). - C99 define un número limitado de métodos de evaluación de expresiones: se puede verificar el modo de compilación actual para garantizar que cumple con los supuestos bajo los cuales se escribió el código.
- Se pueden probar y configurar valores especiales como NaN e infinito positivo o negativo.
long double
se define como precisión doble extendida o cuádruple IEEE 754 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 typedefdouble_t
se puede utilizar para código que sea portable bajo todos losFLT_EVAL_METHOD
).- La función principal a evaluar. Aunque parece que algunos argumentos para esta fracción continua, por ejemplo, 3.0, llevarían a un error de división por cero, de hecho la función está bien definida en 3.0 y la división por 0 simplemente devolverá un +infinito que entonces llevará correctamente a un resultado finito: IEEE 754 está definido para no atrapar tales excepciones de manera predeterminada y está diseñado para que puedan ignorarse muy a menudo, como en este caso. (Si
FLT_EVAL_METHOD
se define como 2, entonces todos los cálculos internos, incluidas las constantes, se realizarán en precisión doble larga; siFLT_EVAL_METHOD
se define como 0, entonces se necesita un cuidado adicional para garantizar esto, incluyendo posiblemente conversiones adicionales y especificación explícita de constantes como doble larga). - Como la flag de división por cero no es un error en este caso, simplemente se puede descartar para borrar la flag para su uso por parte del código posterior.
- En algunos casos, otras excepciones pueden considerarse un error, como un desbordamiento (aunque, de hecho, se puede demostrar que esto no puede ocurrir en este caso).
__STDC_IEC_559__
debe definirse solo si el compilador y la biblioteca C implementan completamente la "aritmética de punto flotante del Anexo F IEC 60559" (los usuarios deben tener en cuenta que esta macro a veces se define cuando no debería estarlo).- El modo de redondeo predeterminado es redondear al más cercano (con la regla de redondeo par en los casos intermedios) para IEEE 754, pero configurar explícitamente el modo de redondeo hacia + y - infinito (al definir
TEST_NUMERIC_STABILITY_UP
, etc. en este ejemplo, al depurar) se puede utilizar para diagnosticar la inestabilidad numérica. [12] Este método se puede utilizar incluso sicompute_fn()
es parte de una biblioteca binaria compilada por separado. Pero dependiendo de la función, no siempre se pueden detectar inestabilidades numéricas.
Detección de versiones
editar
Se define una macro estándar __STDC_VERSION__
con el valor 199901L
para indicar que está disponible el soporte para C99. Al igual que con la macro __STDC__
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
en C90 para evitar errores del enlazador).
#if __STDC_VERSION__ >= 199901L
/* "inline" es una palabra clave */
#else
# define inline static
#endif
Implementaciones
editarLa mayoría de los compiladores de C proporcionan soporte para al menos algunas de las características introducidas en C99.
Compilador | Nivel de soporte | Detalles de compatibilidad con C99 |
---|---|---|
Acorn C/C++ | Parcial | La documentación oficial afirma que "casi todas" las características del compilador, junto con "algunas" funciones de librería son soportadas. |
AMD x86 Open64 Compiler Suite | Completo | Tiene soporte para C99 similar al de GCC.[13] |
cc65 | Parcial | No se implementa la compatibilidad completa con C89 y C99, en parte debido a las limitaciones de la plataforma (MOS Technology 6502). No hay soporte planeado para algunos tipos de C99 como _Complex y enteros de 64 bits (long long ). [14]
|
Ch | Parcial | Soporta las principales características de C99. [15] |
Clang | Completo | Soporta todas las características de C99, excepto los pragmas de punto flotante.[16] |
CompCert | Completo | Un compilador certificado, formalmente comprobado. Admite todas las funciones de C99, excepto los números complejos, los VLA, y restricciones menores en las instrucciones switch (sin Duff's device).[17] |
cparser | Completo | Soporta las características de C99.[18] |
C++ Builder | Completo [cita requerida] |
|
Digital Mars C/C++ Compiler | Parcial | Soporta algunas características, como por ejemplo <tgmath.h> y _Pragma.[19] |
GCC | Completo | A fecha de Julio de 2021, faltan pragmas estándar y soporte para aritmética de punto flotante IEEE 754 / IEC 60559 en la versión principal de GCC. Además, algunas características (como los tipos enteros extendidos y las nuevas funciones de biblioteca) deben ser proporcionadas por la biblioteca estándar de C y están fuera del ámbito de GCC.[20] Las versiones 4.6 y 4.7 de GCC también proporcionan el mismo nivel de cumplimiento..[21][22] Compatibilidad parcial con IEEE 754, incluso cuando el hardware es compatible: es posible que se necesiten algunas opciones del compilador para evitar optimizaciones incorrectas (por ejemplo, -std=c99 y -fsignaling-nans ), pero falta el soporte completo de los modos de redondeo dirigido incluso cuando se usa -frounding-math .[23]
|
Green Hills Software | Full | |
IBM C for AIX, V6 [24] and XL C/C++ V11.1 for AIX [25] | Full | |
IBM Rational logiscope | Full | Hasta Logiscope 6.3, solo se admitían las construcciones básicas de C99. C99 está oficialmente soportado por Logiscope 6.4 y versiones posteriores.[26] |
The Portland Group PGI C/C++ | Full | |
IAR Systems Embedded Workbench |
Mostly | No es compatible con UCN (Unified Character Name). Compilador para objetivos incrustados ("embeded"), como ARM, Coldfire, MSP430, AVR, AVR32, 8051,... No hay objetivos x86. |
Intel C++ compiler | Completo [cita requerida] |
|
Microsoft Visual C++ | Parcial[27] | Visual C++ 2012 y versiones anteriores no eran compatibles con C99.[28][29][30]
Visual C++ 2013 implementa un subconjunto limitado de C99, necesario para compilar proyectos de código abierto populares.[31][32] Visual C++ 2015 implementa la biblioteca estándar C99, con la excepción de las características de la biblioteca que dependen de las características del compilador que aún no son compatibles con el compilador (por ejemplo, <tgmath.h> no está implementado).[27] Visual C++ 2019 (16.6) agrega compatibilidad opcional para un preprocesador compatible con C99.[33] |
Open Watcom | Parcial | Implementa las partes más utilizadas de la norma. Sin embargo, solo se habilitan a través del argumento de línea de comandos -za99 . Tres características de C99 se han agrupado como extensiones de C90 desde la versión anterior a la versión 1.0: comentarios de estilo de C++ (//), arrays de longitud variable, coma final en la declaración de enumeración.[34]
|
Pelles C | Full | Soporta todas las características de C99.[35] |
Portable C compiler | Parcial | Trabajando en conseguir portabilidad completa con C99.[cita requerida] |
Sun Studio | Full[36] | |
The Amsterdam Compiler Kit | No[cita requerida] | Un front-end para C99 está siendo desarrollado.[cita requerida] |
Tiny C Compiler | Parcial | No admite números complejos.[37][38] Los arrays de longitud variable son soportados, pero no como argumentos en las funciones [cita requerida]. Los desarrolladores afirman que "TCC se dirige hacia el cumplimiento total de ISOC99".[39] |
vbcc | Parcial |
Históricamente, Microsoft ha sido lento en implementar nuevas características de C en sus herramientas Visual C++, enfocándose en cambio principalmente en apoyar desarrollos en los estándares de C++. [40] Sin embargo, con la introducción de Visual C++ 2013, Microsoft implementó un subconjunto limitado de C99, que se amplió en Visual C++ 2015.
Trabajo futuro
editarDesde la ratificación del estándar C de 1999, el grupo de trabajo de estándares preparó informes técnicos que especifican soporte mejorado para procesamiento integrado, tipos de datos de caracteres adicionales (soporte Unicode ) y funciones de biblioteca con verificación de límites mejorada. Se continúa trabajando 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 multi-hilo .
La siguiente revisión de la norma C, C11, fue ratificada en 2011. [41] El comité de estándares C adoptó pautas que limitaron la adopción de nuevas características que no hayan sido probadas por implementaciones existentes. Se invirtió mucho esfuerzo en desarrollar un modelo de memoria, con el fin de aclarar los puntos de secuencia y admitir la programación multi-hilo .
Véase también
editarReferencias
editar- ↑ «ISO/IEC 9899:1999 - Programming languages - C». Iso.org. 8 de diciembre de 2011. Consultado el 8 de abril de 2014.
- ↑ a b «IEEE 754 Support in C99». IEEE. Archivado desde el original el 28 de octubre de 2017. Consultado el 15 de julio de 2021.
- ↑ «Standards - Using the GNU Compiler Collection (GCC)». Gcc.gnu.org. Consultado el 8 de abril de 2014.
- ↑ «C Dialect Options - Using the GNU Compiler Collection (GCC)». Gcc.gnu.org. 6 de mayo de 2009. Consultado el 8 de abril de 2014.
- ↑ «Using the GNU Compiler Collection (GCC): Designated Initializers». gnu.org. Consultado el 18 September 2019.
- ↑ «Using the GNU Compiler Collection (GCC): Compound Literals». gnu.org. Consultado el 31 January 2016.
- ↑ Ulrich Drepper (23 de octubre de 2007). «What every programmer should know about memory». LWN.net. Consultado el 3 de abril de 2015.
- ↑ ISO/IEC 9899:1999 specification, TC3. p. 119, § 6.7.5.3 Function declarators (including prototypes) para. 7.
- ↑ Doug Priest (1997). «Differences Among IEEE 754 Implementations».
- ↑ Jack Woehr (1 November 1997). «A conversation with William Kahan.».
- ↑ William Kahan (11 June 1996). «The Baleful Effect of Computer Benchmarks upon Applied Mathematics, Physics and Chemistry».
- ↑ William Kahan (11 January 2006). «How Futile are Mindless Assessments of Roundoff in Floating-Point Computation?».
- ↑ «Using the x86 Open64 Compiler Suite». Developer.amd.com. Archivado desde el original el 24 January 2022. Consultado el 2 March 2022.
- ↑ «cc65 - a freeware C compiler for 6502 based systems». Consultado el 14 September 2011.
- ↑ «C/C++ interpreter Ch C99 features». SoftIntegration, Inc. 15 February 2008. Consultado el 15 February 2008.
- ↑ «Clang Compiler User's Manual». Consultado el 14 October 2017.
- ↑ «The CompCert C verified compiler documentation and user's manual (Version 3.10)». 19 November 2021. Consultado el 3 March 2022.
- ↑ «libfirm homepage». Consultado el 4 February 2014.
- ↑ «C Language Implementation - Digital Mars». Consultado el 14 September 2011.
- ↑ «Status of C99 features in GCC». Free Software Foundation, Inc. 28 July 2021. Consultado el 13 August 2021.
- ↑ «Status of C99 features in GCC 4.6». Free Software Foundation, Inc. 23 de mayo de 2013. Consultado el 23 de mayo de 2013.
- ↑ «Status of C99 features in GCC 4.7». Free Software Foundation, Inc. 23 de mayo de 2013. Consultado el 23 de mayo de 2013.
- ↑ «Semantics of Floating Point Math in GCC». 20 July 2018. Consultado el 12 August 2018.
- ↑ «IBM C for AIX, V6.0 Now Supports the C99 Standard». 2 July 2002. Consultado el 31 January 2016.
- ↑ «IBM - XL C/C++ for AIX». Consultado el 31 January 2016.
- ↑ «IBM Rational Logiscope support for C99 standard - United States». 24 February 2012. Consultado el 31 January 2016.
- ↑ a b Brenner, Pat. «What's New for Visual C++ in Visual Studio 2015». Microsoft Developer Network. Consultado el 27 April 2015.
- ↑ «Reader Q&A: What about VC++ and C99?». Sutter’s Mill. 3 de mayo de 2012. Consultado el 31 January 2016.
- ↑ «A.27 Use of C99 Variable Length Arrays». Microsoft. Consultado el 31 January 2016.
- ↑ «Microsoft to C99 Developers: Use ISO C++». InfoQ. Consultado el 31 January 2016.
- ↑ «C99 library support in Visual Studio 2013». Microsoft. 19 July 2013. Consultado el 31 January 2016.
- ↑ «C++11/14 STL Features, Fixes, And Breaking Changes In VS 2013». Blogs.msdn.com. 28 de junio de 2013. Consultado el 8 de abril de 2014.
- ↑ «Announcing full support for a C/C++ conformant preprocessor in MSVC». Microsoft. 27 March 2020. Consultado el 17 September 2020.
- ↑ «C99 compliance in Open Watcom». Archivado desde el original el 3 de mayo de 2015. Consultado el 25 September 2015.
- ↑ «Pelles C Overview». January 2013. Archivado desde el original el 13 March 2022. Consultado el 2 March 2022.
- ↑ «Sun Studio 12: C Compiler 5.9 Readme». Sun Microsystems, Inc. 31 de mayo de 2007. Consultado el 23 September 2012.
- ↑ «Tiny C Compiler Reference Documentation». Consultado el 31 January 2016.
- ↑ According to the project's TODO list complex types are the only missing C99 feature. Variable Length Arrays have been added in TCC 0.9.26 [1]
- ↑ «TCC : Tiny C Compiler». Consultado el 31 January 2016.
- ↑ Peter Bright (29 June 2013). «C99 acknowledged at last as Microsoft lays out its path to C++14». Ars Technica. Consultado el 9 January 2015.
- ↑ «Standards - Using the GNU Compiler Collection (GCC)». Gcc.gnu.org. Consultado el 8 de abril de 2014.
Lectura adicional
editar- N1256 (borrador final de la norma C99 más TC1, TC2, TC3); WG14; 2007. ( versiones HTML y ASCII )
- ISO/IEC 9899:1999 (norma oficial C99); ISO ; 1999.
- Fundamento del documento C99 ; WG14; 2003.