estandar - ¿Cuáles son las nuevas características más útiles en C99?
estandar c99 (17)
Arrays de longitud variable:
int x;
scanf("%d", &x);
int a[x];
for (int i = 0; i < x; ++i)
a[i] = i * i;
for (int i = 0; i < x; ++i)
printf("%d/n", a[i]);
C99 ha existido por más de 10 años, pero el soporte ha sido lento, por lo que la mayoría de los desarrolladores se han quedado con C89. Incluso hoy, a veces me sorprende un poco cuando me encuentro con las características C99 en el código C.
Ahora que la mayoría de los compiladores principales admiten C99 (una excepción notable es MSVC y algunos compiladores incrustrados también están rezagados), creo que los desarrolladores que trabajan con C probablemente deberían saber qué funciones de C99 están disponibles para ellos. Algunas de las funciones son solo características comunes que nunca fueron estandarizadas antes ( snprintf
, por ejemplo), o están familiarizadas con C ++ (colocación flexible de declaraciones de variables, o comentarios //
sola línea), pero algunas de las nuevas características se introdujeron por primera vez en C99 y no son familiares para muchos programadores.
¿Cuáles son las características nuevas más útiles en C99?
Como referencia, el estándar C99 (etiquetado como un borrador, pero idéntico al estándar actualizado, hasta donde yo sé), la lista de nuevas características y el estado de implementación GCC C99 .
Una característica por respuesta, por favor; Siéntase libre de dejar respuestas múltiples. Se alientan ejemplos de códigos cortos que demuestran nuevas características.
Constantes de coma flotante hexadecimales ( 0x1.8p0f
) y especificadores de conversión ( %a
, %A
). Si maneja los detalles numéricos de bajo nivel con frecuencia, estos son una mejora enorme sobre los literales y las conversiones decimales.
Le ahorran preocupaciones sobre el redondeo cuando especifica constantes para un algoritmo, y son inmensamente útiles para depurar código de coma flotante de bajo nivel.
Creo que los nuevos mecanismos de inicialización son extremadamente importantes.
struct { int x, y; } a[10] = { [3] = { .y = 12, .x = 1 } };
OK - no es un ejemplo convincente, pero la notación es precisa. Puede inicializar elementos específicos de una matriz y miembros específicos de una estructura.
Tal vez un mejor ejemplo sea este, aunque admito que no es muy convincente:
enum { Iron = 26, Aluminium = 13, Beryllium = 4, ... };
const char *element_names[] =
{
[Iron] = "Iron",
[Aluminium] = "Aluminium",
[Beryllium] = "Beryllium",
...
};
El tipo bool.
Ahora puede hacer algo como eso:
bool v = 5;
printf("v=%u/n", v);
imprimirá
1
Estoy tan acostumbrado a escribir
for (int i = 0; i < n; ++i) { ... }
en C ++ que es un dolor usar un compilador no C99 en el que me veo obligado a decir
int i;
for (i = 0; i < n; ++i ) { ... }
La palabra clave restrict
Especialmente cuando crunch números ...
Literales compuestos, ya mencionados, pero aquí está mi convincente ejemplo:
struct A *a = malloc(sizeof(*a));
*a = (struct A){0}; /* full zero-initialization */
/* or */
*a = (struct A){.bufsiz=1024, .fd=2}; /* rest are zero-initialized. */
Es una forma clara de inicializar los datos, incluso si están en el montón. No hay forma de olvidarse de inicializar cero algo.
Literales compuestos. Establecer estructuras miembro por miembro es tan ''89;)
También puede usarlos para obtener punteros a objetos con duración de almacenamiento automática sin declarar variables innecesarias, por ejemplo
foo(&(int){ 4 });
insteand de
int tmp = 4;
foo(&tmp);
Macros variadas. Facilita la generación de código repetitivo con un número ilimitado de argumentos.
Miembros de matriz flexibles.
6.7.2.1 Estructura y especificadores de unión
Como un caso especial, el último elemento de una estructura con más de un miembro nombrado puede tener un tipo de matriz incompleto; esto se llama un miembro de matriz flexible . Con dos excepciones, el miembro de matriz flexible se ignora. Primero, el tamaño de la estructura debe ser igual al desplazamiento del último elemento de una estructura por lo demás idéntica que reemplaza al elemento de matriz flexible con una matriz de longitud no especificada) Segundo, cuando a
.
(o->
) el operador tiene un operando izquierdo que es (un puntero) una estructura con un miembro de matriz flexible y el operando derecho nombra a ese miembro, se comporta como si ese miembro se reemplazara con la matriz más larga (con el mismo tipo de elemento) ) que no haría la estructura más grande que el objeto al que se accede; el desplazamiento de la matriz seguirá siendo el del elemento de matriz flexible, incluso si esto difiriera del de la matriz de reemplazo. Si esta matriz no tiene elementos, se comporta como si tuviera un elemento, pero el comportamiento no está definido si se intenta acceder a ese elemento o generar un puntero pasado.
Ejemplo:
typedef struct {
int len;
char buf[];
} buffer;
int bufsize = 100;
buffer *b = malloc(sizeof(buffer) + sizeof(int[bufsize]));
Personalmente, me gusta el reconocimiento de IEC 60559: 1989 (aritmética binaria en coma flotante para sistemas de microprocesador) y mucho mejor soporte de coma flotante.
En una línea similar, configurar y consultar el modo de redondeo de coma flotante, verificar si hay números Nan / Infinito / subnormales, etc., es bueno tenerlos.
Poder declarar variables en ubicaciones distintas al inicio de un bloque.
Soporte de secuencia de escape Unicode:
printf("It''s all /u03B5/u03BB/u03BB/u03B7/u03BD/u03B9/u03BA/u03AC to me./n");
O incluso, caracteres literales Unicode:
printf("日本語/n");
(nota: puede no funcionar dependiendo de su configuración regional; el soporte portátil para diferentes codificaciones requerirá más trabajo que este)
Soporte para comentarios de una línea que comienzan con //
.
Soporte para funciones en inline
.
stdint.h
, que define int8_t
, uint8_t
, etc. Ya no uint8_t
que hacer suposiciones no portátiles sobre qué tan ancho son tus enteros.
uint32_t truth = 0xDECAFBAD;
snprintf()
- en serio, vale la pena mucho poder hacer cadenas con formato seguro.