Acabo de leer: C entrada de Wikipedia. Hasta donde sé, hay 3 versiones diferentes de C que se usan ampliamente: C89, C99 y C11. Mi pregunta se refiere a la compatibilidad del código fuente de diferentes versiones. Supongamos que voy a escribir un programa (en C11 ya que es la última versión) e importar una biblioteca escrita en C89. ¿Estas dos versiones funcionarán juntas correctamente al compilar todos los archivos de acuerdo con la especificación C11?

Pregunta 1 : ¿Son las versiones más nuevas de C, es decir, C99, C11 supersets de versiones anteriores de C? Por superconjunto quiero decir que ese código antiguo se compilará sin errores y el mismo significado cuando se compila de acuerdo con las nuevas especificaciones de C.

Acabo de leer que // tiene diferentes significados en C89 y C99. Además de esta función, ¿son los superconjuntos C99 y C11 de C89?

Si la respuesta a la pregunta 1 es no, entonces tengo otras 2 preguntas.

  1. ¿Cómo 'portar' el código antiguo a las nuevas versiones? ¿Hay algún documento que explique este procedimiento?

  2. ¿Es mejor usar C89 o C99 o C11?

Gracias por su ayuda de antemano.

EDITAR : cambió ISO C a C89.

11
Michael S 8 ene. 2017 a las 21:00

4 respuestas

La mejor respuesta

¿Son las versiones más nuevas de C, es decir, C99, C11 supersets de versiones anteriores de C?

Hay muchas diferencias, grandes y sutiles ambos. La mayoría de los cambios fueron la adición de nuevas características y bibliotecas. C99 y C11 no son superconjuntos de C90, aunque se hizo un gran esfuerzo para garantizar la compatibilidad con versiones anteriores. Sin embargo, C11 es principalmente un superconjunto de C99.

Un código aún más antiguo podría romperse al portar desde C90, en caso de que el código se haya escrito mal. Particularmente varias formas de "int implícito" y declaraciones de funciones implícitas fueron prohibidas del lenguaje con C99. C11 prohibió la función gets.

Se puede encontrar una lista completa de los cambios en el borrador de C11, página 13 de pdf, donde" la tercera edición "se refiere a C11 y" la segunda edición "se refiere a C99.

¿Cómo 'portar' el código antiguo a las nuevas versiones? ¿Hay algún documento que explique este procedimiento?

No conozco ningún documento de este tipo. Si tiene un buen código, la portabilidad es fácil. Si tiene un código podrido, la transferencia será dolorosa. En cuanto al procedimiento de transferencia real, será fácil si conoce los conceptos básicos de C99 y C11, por lo que la mejor opción es encontrar una fuente confiable de aprendizaje que aborde C99 / C11.

La transferencia de C99 a C11 debe ser sin esfuerzo.

¿Es mejor usar C89 o C99 o C11?

Es mejor usar C11 ya que ese es el estándar actual. C99 y C11 contenían varias "correcciones de errores de idioma" e introdujeron características nuevas y útiles.

11
Lundin 9 ene. 2017 a las 10:02

Las versiones más nuevas de C definitivamente no son superconjuntos estrictos de las versiones anteriores.

En términos generales, este tipo de problema solo surge cuando se actualiza el compilador o se cambian los proveedores del compilador. Debe planear muchos toques menores del código para lidiar con este evento. Muchas veces, el nuevo compilador detectará problemas que no fueron diagnosticados por el compilador anterior, además de pequeñas incompatibilidades que pueden haber ocurrido al aplicar el estándar C más reciente.

Si es posible determinar, el mejor estándar para usar es el que el compilador admite mejor.

El artículo de Wikipedia C11 tiene una larga descripción de cómo difiere de C99.

0
jxh 8 ene. 2017 a las 19:00

En general, las versiones más nuevas del estándar son compatibles con versiones anteriores.

Si no, puede compilar diferentes archivos .c en diferentes archivos .o, utilizando diferentes estándares, y vincularlos. Eso funciona

En general, debe usar el estándar más nuevo disponible para el nuevo código y, si es fácil, corregir el código que rompe el nuevo estándar en lugar de usar la solución hacky anterior.

EDITAR : a menos que esté lidiando con un comportamiento potencialmente indefinido.

0
Paul Stelian 11 ene. 2017 a las 06:54

En la mayoría de los casos, las versiones posteriores son superconjuntos de versiones anteriores. Mientras que el código C89 que intenta usar restrict como identificador se romperá con la adición de C99 de una palabra reservada con la misma ortografía, y mientras hay algunas situaciones en las que el código está diseñado para explotar algunos casos de esquina con un analizador sintáctico serán tratados de manera diferente en los dos idiomas, la mayoría de ellos es poco probable que sean importantes.

Sin embargo, una cuestión más importante tiene que ver con el alias de memoria. C89 incluye reglas que restringen los tipos de punteros que pueden usarse para acceder a ciertos objetos. Dado que las reglas habrían hecho que funciones como malloc () fueran inútiles si se aplicaron, tal como están escritos, a los objetos creados de ese modo, la mayoría de los programadores y los escritores del compilador trataron las reglas como aplicando solo en casos limitados (dudo que C89 hubiera sido ampliamente aceptado si la gente no creyera que las reglas se aplicaban solo de manera limitada) C99 afirmó "aclarar" las reglas, pero sus nuevas reglas tienen un efecto mucho más expansivo que las interpretaciones contemporáneas de las antiguas, rompiendo una gran cantidad de código que habría tenido un comportamiento definido bajo esas interpretaciones comunes de C89, e incluso algún código que habría sido definido inequívocamente bajo C89 no tiene equivalente práctico C99.

En C89, por ejemplo, memcpy podría usarse para copiar el patrón de bits asociado con un objeto de cualquier tipo a un objeto de cualquier otro tipo con el mismo tamaño, en cualquier caso donde ese patrón de bits representaría un valor válido en el tipo de destino C99 agregó lenguaje que permite que los compiladores se comporten de manera arbitraria si se usa memcpy para copiar un objeto de algún tipo T en el almacenamiento sin tipo declarado (por ejemplo, el almacenamiento devuelto desde malloc), y ese almacenamiento es entonces leer como objeto de un tipo que no es compatible con alias con T, incluso si el patrón de bits del objeto original tendría un significado válido en el nuevo tipo. Además, las reglas que se aplican a memcpy también se aplican en los casos en que un objeto se copia como una matriz de tipo de caracteres, sin aclarar exactamente lo que eso significa, por lo que no está claro exactamente qué código debería hacer para lograr un comportamiento que coincida con el C89 memcpy.

En muchos compiladores, estos problemas se pueden resolver agregando una opción -fno-strict-aliasing a la línea de comandos. Tenga en cuenta que especificar el modo C89 puede no ser suficiente, ya que los escritores de compiladores a menudo usan la misma semántica de memoria independientemente del estándar que se supone que deben implementar.

1
supercat 9 ene. 2017 a las 21:50