¿Cuáles son las nuevas funciones más útiles de C99? [cerrado]

78

C99 ha existido durante más de 10 años, pero su soporte ha sido lento, por lo que la mayoría de los desarrolladores se han quedado con C89. Incluso hoy en día, a veces me sorprende un poco cuando me encuentro con las funciones de C99 en el código C.

Ahora que la mayoría de los principales compiladores admiten C99 (MSVC es una excepción notable y algunos compiladores integrados también se quedan atrás), creo que los desarrolladores que trabajan con C probablemente deberían saber qué características de C99 están disponibles para ellos. Algunas de las características son solo características comunes que nunca se estandarizaron antes ( snprintfpor ejemplo), o son familiares de C ++ (ubicación de declaración de variable flexible o //comentarios de una sola línea ), pero algunas de las características nuevas se introdujeron por primera vez en C99 y son desconocido para muchos programadores.

¿Cuáles le parecen las nuevas funciones más útiles de C99?

Como referencia, el estándar C99 (etiquetado como borrador, pero idéntico al estándar actualizado, hasta donde yo sé), la lista de nuevas características y el estado de implementación de GCC C99 .

Una función por respuesta, por favor; no dude en dejar varias respuestas. Se recomiendan ejemplos de código corto que demuestren nuevas características.

Brian Campbell
fuente
2
¡Debería haber una wiki similar para las características que la gente odia en C99!
Alok Singhal
Bueno, hubo una pregunta sobre las características dañinas o no compatibles de C99 stackoverflow.com/questions/1898890/…
Brian Campbell
Gracias. Debe cambiar el texto del vínculo para indicar que es un borrador, no el estándar real, y vincularlo a n1256 mientras lo hace :-). Por cierto, mirando gcc.gnu.org/c99status.html , no diría que la mayor parte de C99 es compatible con gcc. Y dado que gcc es uno de los compiladores de C más utilizados, ...
Alok Singhal
2
Tenga en cuenta que en el ámbito de los procesadores integrados, es posible que C99 aún no sea bien compatible.
Craig McQueen
1
@Alok Yo llamaría a ese nivel de soporte la mayoría de las funciones; Supongo que depende de cómo lo defina, pero creo que la mayoría de las características importantes que la gente quiere usar son compatibles, dejando de lado algunos problemas de biblioteca. @Craig Bastante justo, agregó un descargo de responsabilidad sobre los compiladores integrados.
Brian Campbell

Respuestas:

77

Estoy tan acostumbrado a escribir

en C ++ que es una molestia usar un compilador que no sea C99 donde me veo obligado a decir

Jon Reid
fuente
44
Además, reduce el alcance de la variable int, lo cual siempre es bueno ^^
helpermethod
Esa también sería mi elección.
figurassa 12/01/10
2
@Oliver <sarcasm> ¡pero luego las instrucciones sub esp, 4y add esp, 4se eliminan! </sarcasm>
Cole Johnson
72

stdint.h, Que define int8_t, uint8_tetc. Ya no tendrá que hacer suposiciones no portátiles sobre el ancho de sus números enteros son.

Brian Campbell
fuente
19
La mejor frase hexadecimal desde DE: AD: BE: EF: CA: FE.
Kevin L.
¿Qué se supone que significa decafbad?
Pacerier
5
@Pacerier Es solo una constante hexadecimal arbitraria que se usa para ilustrar el ejemplo. Pero para el valor del humor, se deletrea "descafeinado malo", lo que implica que el café descafeinado es inferior al real.
Brian Campbell
5
ok, no puedo relacionarme con su humor ...
Pacerier
66

Creo que los nuevos mecanismos de inicialización son extremadamente importantes.

Bien, 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.

Quizás un mejor ejemplo sería este, aunque admito que no es muy convincente:

Jonathan Leffler
fuente
6
Esa es una demostración convincente. Hay una gran cantidad de tablas de enumeración con las tablas de cadenas correspondientes.
u0b34a0f6ae
5
@ColeJohnson: Si observa detenidamente el segundo ejemplo, observará que los inicializadores están desordenados, pero funcionarán correctamente. Eso no se puede hacer simplemente con define. El primer ejemplo inicializa solo el índice 4 de la matriz; eso tampoco se puede hacer simplemente con define.
Jonathan Leffler
2
También debe tenerse en cuenta que usar el mismo índice más de una vez anulará el primer uso con el segundo; vea mi pregunta aquí, por ejemplo: stackoverflow.com/questions/16742467/…
johnny
51

Matrices de longitud variable:

mmx
fuente
3
¿De verdad crees que las matrices VLA son tan buenas? C11 los hace opcionales.
Bosón Z
3
Simplemente no olvide aplicar el saneamiento de entrada para evitar un desbordamiento de la pila (o corrupción de la pila, si x es negativo):if (x < 0) x = 0; else if (x > 1024) x = 1024;
Andrew D'Addesio
51

Soporte para comentarios de una línea comenzando por //.

gameover
fuente
7
+1 TODOS los compiladores que conozco ya admiten esto. Ya es hora de que se mencione en la norma.
slebetman
41

Poder declarar variables en ubicaciones distintas al inicio de un bloque.

mikecsh
fuente
2
No estoy tan interesado en esto. En mi opinión, las variables no solo deben incluirse en el alcance cuando sea necesario, sino también eliminarlas cuando no se necesiten. Las variables a mitad de bloque casi invariablemente permanecen en el alcance más tiempo del que deberían.
supercat
5
@supercat prefiere int a; int b; a = f(); b = g();a int a = f(); int b = g();? declarar una variable cerca de donde se inicializa es enorme para reducir errores.
Ryan Haining
@RyanHaining:. Por otra parte, crear un bloque anidado alcance (sólo desearía que era una sintaxis estándar, que dijo que "este bloque es sólo para la determinación del alcance", uno puede utilizar simplemente utilizar una macro nulo para ese propósito, pero que parece un poco feo
supercat
@supercat Hay una sintaxis estándar para eso: /* this block is just for scoping */ { } /* scope */:)
alx
@CacahueteFrito: Creo que if(1) /* Scoping block */ { }es un poco mejor, pero un problema mayor es que el alcance y el control son conceptos ortogonales. Si bien hay ocasiones en las que tiene sentido establecer el alcance de las cosas dentro de un bucle, a menudo es útil tener las cosas dentro del alcance alrededor del bucle, y también hay muchas ocasiones en las que el código creará objetos para mantener valores que serán necesarios en la creación de objetos de vida más larga, pero nunca después de eso (por ejemplo, float dx=x2-x1, dy=y2-y1; float distance = sqrt(dx*dx+dy*dy);no hay razón dx y debería necesitar ser mantenido en su alcance dy..
supercat
36

Macros variadic. Facilita la generación de código repetitivo con un número ilimitado de argumentos.

Kennytm
fuente
34

snprintf() - En serio, vale mucho la pena poder hacer cadenas formateadas seguras.

David Thornley
fuente
1
Muy cierto. Iba a agregar esta respuesta yo mismo si nadie más lo hizo.
Brian Campbell
29

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ático sin declarar variables innecesarias, por ejemplo

en el lugar de

Christoph
fuente
Debería asignar memoria en la pila para 4, ¿verdad?
AlphaGoku
29

Miembros de matriz flexibles.

6.7.2.1 Especificadores de estructura y unión

Como caso especial, el último elemento de una estructura con más de un miembro nombrado puede tener un tipo de matriz incompleta; esto se denomina miembro de matriz flexible . Con dos excepciones, se ignora el miembro de matriz flexible. Primero, el tamaño de la estructura será igual al desplazamiento del último elemento de una estructura idéntica que reemplaza el miembro de la matriz flexible con una matriz de longitud no especificada) Segundo, cuando a .(o->) tiene un operando izquierdo que es (un puntero a) una estructura con un miembro de matriz flexible y el operando derecho nombra ese miembro, se comporta como si ese miembro fuera reemplazado por la matriz más larga (con el mismo tipo de elemento) que no hacer la estructura más grande que el objeto al que se accede; el desplazamiento de la matriz seguirá siendo el del miembro de matriz flexible, incluso si esto difiera del de la matriz de reemplazo. Si esta matriz no tuviera elementos, se comporta como si tuviera un elemento, pero el comportamiento es indefinido si se intenta acceder a ese elemento o generar un puntero uno más allá de él.

Ejemplo:

Gregory Pakosz
fuente
2
+1 por finalmente hacer esto kosher. Está en todos los códigos de socket TCP / IP que he visto.
slebetman
De hecho, lo consideraría mucho más kosher que el truco común de usar buf [1] y restar 1 del tamaño de malloc. El truco puede ser común, pero lo consideraría un comportamiento indefinido (lo correcto sería usar buf [MAX_SIZE] y restar MAX_SIZE del tamaño de malloc) ya que el código de indexación generado por un compilador puede depender del tamaño percibido de buf [].
supercat
25

El tipo bool.

Ahora puedes hacer algo como eso:

imprimirá

Patrick Schlüter
fuente
2
Quien haya pensado en esto es puro genio
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
No, boolen C99 coacciona el valor asignado a la variable para que sea siempre 1 o 0. Por eso hay que tener cuidado si tiene código que se ejecuta en un compilador C99 y en uno más antiguo con tipo "simulado" bool. El uso !!lo hará portátil. v = !!5;tiene la misma semántica, pero no es tan legible.
Patrick Schlüter
¿imprimirá 1 al asignar un número par como 6?
phuclv
Si. Cualquier valor distinto de cero será reemplazado por 1.
Patrick Schlüter
18

Soporte para inlinefunciones.

CodeRain
fuente
En la práctica, GCC generalmente ignora la palabra clave en línea al decidir qué funciones incluir en línea, y automáticamente inserta cosas en función de sus propias heurísticas, a menos que lo fuerce a hacer lo contrario.
daf
7
daf: inlinetodavía ayuda, porque le permite definir la función en más de una unidad de traducción, por lo que puede colocarla en un archivo de encabezado, lo que brinda oportunidades de inserción entre módulos.
caf
@dafinline __attribute__((force_inline))
Cole Johnson
18

Literales compuestos, ya mencionados, pero aquí está mi ejemplo convincente:

Es una forma clara de inicializar datos incluso si están en el montón. No hay forma de olvidarse de inicializar a cero algo.

u0b34a0f6ae
fuente
17

La restrictpalabra clave. Especialmente cuando haces números ...

Alexandre C.
fuente
15

Soporte de secuencia de escape Unicode:

O incluso, caracteres Unicode literales:

(nota: es posible que no funcione según su ubicación; el soporte portátil para diferentes codificaciones requerirá más trabajo que esto)

Brian Campbell
fuente
12

Constantes hexadecimales de coma flotante ( 0x1.8p0f) y especificadores de conversión ( %a, %A). Si trabaja con detalles numéricos de bajo nivel con frecuencia, estos son una mejora enorme con respecto a las conversiones y literales decimales.

Le ahorran las preocupaciones sobre el redondeo al especificar constantes para un algoritmo y son inmensamente útiles para depurar código de punto flotante de bajo nivel.

Stephen Canon
fuente
3
Sí, los usé el otro día cuando trataba de explicarle a alguien cómo funcionan los números de punto flotante en otra pregunta de Stack Overflow.
Brian Campbell
9

Personalmente, me gusta el reconocimiento de IEC 60559: 1989 (aritmética de punto flotante binario para sistemas de microprocesador) y mucho mejor soporte de punto flotante.

De manera similar, configurar y consultar el modo de redondeo de punto flotante, verificar números Nan / Infinity / subnormales, etc., es excelente.

Alok Singhal
fuente
Bueno, a MS no le gusta hacer esto
Cole Johnson
C no está realmente bien diseñado para el concepto de modos de redondeo, ya que significa que las matemáticas de punto flotante deben tratarse como si tuvieran efectos secundarios. Tener algo mejor que la semántica de punto flotante de "esperanza para lo mejor" es útil, pero no sé cuántas implementaciones realmente cumplen con todos los requisitos del Anexo F.
supercat