stringtranslate.com

Compatibilidad de C y C++

Los lenguajes de programación C y C++ están estrechamente relacionados, pero tienen muchas diferencias significativas. C++ comenzó como una bifurcación de un C temprano, pre- estandarizado , y fue diseñado para ser mayormente compatible en código fuente y enlace con los compiladores de C de la época. [1] [2] Debido a esto, las herramientas de desarrollo para los dos lenguajes (como IDE y compiladores ) a menudo se integran en un solo producto, y el programador puede especificar C o C++ como su lenguaje fuente.

Sin embargo, C no es un subconjunto de C++, [3] y los programas C no triviales no se compilarán como código C++ sin modificaciones. Asimismo, C++ presenta muchas características que no están disponibles en C y en la práctica casi todo el código escrito en C++ no es código C conforme. Este artículo, sin embargo, se centra en las diferencias que hacen que el código C conforme sea código C++ mal formado, o que sea conforme/bien formado en ambos lenguajes pero que se comporte de manera diferente en C y C++.

Bjarne Stroustrup , el creador de C++, ha sugerido [4] que las incompatibilidades entre C y C++ deberían reducirse tanto como sea posible para maximizar la interoperabilidad entre los dos lenguajes. Otros han argumentado que, dado que C y C++ son dos lenguajes diferentes, la compatibilidad entre ellos es útil pero no vital; según este grupo, los esfuerzos por reducir la incompatibilidad no deberían obstaculizar los intentos de mejorar cada lenguaje de forma aislada. La justificación oficial del estándar C de 1999 ( C99 ) "respaldó el principio de mantener el subconjunto común más grande" entre C y C++ "mientras se mantiene una distinción entre ellos y se les permite evolucionar por separado", y declaró que los autores estaban "contentos con dejar que C++ sea el lenguaje grande y ambicioso". [5]

Varias adiciones de C99 no son compatibles con el estándar C++ actual o entran en conflicto con características de C++, como las matrices de longitud variable , los tipos de números complejos nativos y el restrict calificador de tipo . Por otro lado, C99 redujo algunas otras incompatibilidades en comparación con C89 al incorporar características de C++ como //comentarios y declaraciones y código mixtos. [6]

Construcciones válidas en C pero no en C++

C++ aplica reglas de tipado más estrictas (no se permiten violaciones implícitas del sistema de tipos estáticos [1] ) y requisitos de inicialización (aplicación en tiempo de compilación de que las variables dentro del ámbito no tengan una inicialización subvertida) [7] que C, por lo que parte del código C válido no es válido en C++. En el Anexo C.1 del estándar ISO C++ se ofrece una justificación de esto. [8]

C99 y C11 agregaron varias características adicionales a C que no se habían incorporado al C++ estándar a partir de C++20 , como números complejos, matrices de longitud variable (los números complejos y las matrices de longitud variable se designan como extensiones opcionales en C11), miembros de matriz flexibles , la palabra clave restrict , calificadores de parámetros de matriz y literales compuestos .

C++ agrega numerosas palabras clave adicionales para respaldar sus nuevas funciones. Esto hace que el código C que utilice esas palabras clave como identificadores no sea válido en C++. Por ejemplo:

plantilla de estructura { int nuevo ; plantilla de estructura * clase ; };       
es un código C válido, pero es rechazado por un compilador de C++, ya que las palabras claves templatey están reservadas new.class

Construcciones que se comportan de manera diferente en C y C++

Hay algunas construcciones sintácticas que son válidas tanto en C como en C++ pero producen resultados diferentes en los dos lenguajes.

Varias de las otras diferencias con respecto a la sección anterior también se pueden aprovechar para crear código que se compile en ambos lenguajes pero que se comporte de manera diferente. Por ejemplo, la siguiente función devolverá valores diferentes en C y C++:

externo int T ;  int tamaño ( void ) { struct T { int i ; int j ; }; devolver tamañode ( T ); /* C: devolver tamañode(int)  * C++: devolver tamañode(struct T)  */ }             

Esto se debe a que C requiere structdelante de las etiquetas de estructura (y por lo tanto sizeof(T)se refiere a la variable), pero C++ permite que se omita (y por lo tanto sizeof(T)se refiere al implícito typedef). Tenga en cuenta que el resultado es diferente cuando la externdeclaración se coloca dentro de la función: entonces, la presencia de un identificador con el mismo nombre en el ámbito de la función inhibe que el implícito typedefsurta efecto para C++, y el resultado para C y C++ sería el mismo. Observe también que la ambigüedad en el ejemplo anterior se debe al uso del paréntesis con el sizeofoperador. El uso sizeof Tesperaría Tser una expresión y no un tipo, y por lo tanto, el ejemplo no se compilaría con C++.

Vinculación de código C y C++

Si bien C y C++ mantienen un alto grado de compatibilidad de código fuente, los archivos de objetos que producen sus respectivos compiladores pueden tener diferencias importantes que se manifiestan al mezclar código C y C++. En particular:

Por estos motivos, para que el código C++ llame a una función C foo(), el código C++ debe crear un prototipo foo() con extern "C". Del mismo modo, para que el código C llame a una función C++ bar(), el código C++ para bar()debe declararse con extern "C".

Una práctica común para que los archivos de encabezado mantengan la compatibilidad con C y C++ es hacer que su declaración sea extern "C"para el alcance del encabezado: [22]

/* Archivo de encabezado foo.h */ #ifdef __cplusplus /* Si se trata de un compilador de C++, utilice el enlace C */ extern "C" { #endif  /* Estas funciones obtienen enlace C */ void foo (); struct bar { /* ... */ };      #ifdef __cplusplus /* Si este es un compilador de C++, finaliza el enlace de C */ } #endif

Las diferencias entre las convenciones de vinculación y llamada de C y C++ también pueden tener implicaciones sutiles para el código que utiliza punteros de función . Algunos compiladores producirán código que no funciona si un puntero de función declarado extern "C"apunta a una función de C++ que no está declarada extern "C". [23]

Por ejemplo, el siguiente código:

void mi_funcion (); externo "C" void foo ( void ( * fn_ptr )( void ));    barra vacía () { foo ( mi_funcion );}

Al utilizar el compilador C++ de Sun Microsystems , esto produce la siguiente advertencia:

 $ CC - c test . cc    "test.cc" , línea 6 : Advertencia ( anacronismo ) : El argumento formal fn_ptr del tipo extern "C" void ( * )() en la llamada a foo ( extern "C" void ( * )()) se está pasando void ( * )().                       

Esto se debe a que my_function()no se declara con las convenciones de llamada y enlace de C, sino que se pasa a la función de foo()C.

Referencias

  1. ^ ab Stroustrup, Bjarne . "An Overview of the C++ Programming Language in The Handbook of Object Technology (Editor: Saba Zamir). CRC Press LLC, Boca Raton. 1999. ISBN 0-8493-3135-8" (PDF) . p. 4. Archivado (PDF) desde el original el 16 de agosto de 2012 . Consultado el 12 de agosto de 2009 .
  2. ^ B.Stroustrup. "C y C++: hermanos. The C/C++ Users Journal. Julio de 2002" (PDF) . Consultado el 17 de marzo de 2019 .
  3. ^ "Preguntas frecuentes de Bjarne Stroustrup: ¿C es un subconjunto de C++?" . Consultado el 22 de septiembre de 2019 .
  4. ^ B. Stroustrup. "C y C++: un caso de compatibilidad. The C/C++ Users Journal. Agosto de 2002" (PDF) . Archivado (PDF) desde el original el 22 de julio de 2012. Consultado el 18 de agosto de 2013 .
  5. ^ Fundamento del Estándar Internacional —Lenguajes de Programación—C Archivado el 6 de junio de 2016 en Wayback Machine , revisión 5.10 (abril de 2003).
  6. ^ "Opciones del dialecto C: uso de la colección de compiladores GNU (GCC)". gnu.org . Archivado desde el original el 26 de marzo de 2014.
  7. ^ "N4659: Borrador de trabajo, Norma para el lenguaje de programación C++" (PDF) . §Anexo C.1. Archivado (PDF) desde el original el 7 de diciembre de 2017.("No es válido omitir una declaración con inicializador explícito o implícito (excepto en todo el bloque no ingresado). … Con esta simple regla de tiempo de compilación, C++ asegura que si una variable inicializada está dentro del alcance, entonces con certeza ha sido inicializada").
  8. ^ "N4659: Borrador de trabajo, Norma para el lenguaje de programación C++" (PDF) . §Anexo C.1. Archivado (PDF) desde el original el 7 de diciembre de 2017.
  9. ^ "Centro de conocimiento de IBM". ibm.com .
  10. ^ "Preguntas frecuentes > Casting malloc - Cprogramming.com". faq.cprogramming.com . Archivado desde el original el 5 de abril de 2007.
  11. ^ "4.4a — Conversión explícita de tipos (casting)". 16 de abril de 2015. Archivado desde el original el 25 de septiembre de 2016.
  12. ^ "Funciones de la biblioteca estándar que preservan calificadores, v4" (PDF) .
  13. ^ "longjmp - Referencia de C++". www.cplusplus.com . Archivado desde el original el 19 de mayo de 2018.
  14. ^ "WG14 N2432: Eliminar soporte para definiciones de funciones con listas de identificadores" (PDF) .
  15. ^ "Borrador de norma ISO C 2011" (PDF) .
  16. ^ "WG14 N 2841: No hay declaradores de funciones sin prototipos".
  17. ^ "std::complex - cppreference.com". es.cppreference.com . Archivado desde el original el 15 de julio de 2017.
  18. ^ "Incompatibilidades entre ISO C e ISO C++". Archivado desde el original el 9 de abril de 2006.
  19. ^ Punteros restringidos Archivado el 6 de agosto de 2016 en Wayback Machine desde Uso de la colección de compiladores GNU (GCC)
  20. ^ "WG14-N2764: El atributo noreturn" (PDF) . open-std.org . 21 de junio de 2021. Archivado (PDF) del original el 25 de diciembre de 2022.
  21. ^ "Centro de conocimiento de IBM". ibm.com .
  22. ^ "Centro de conocimiento de IBM". ibm.com .
  23. ^ "Documentación de Oracle". Docs.sun.com. Archivado desde el original el 3 de abril de 2009. Consultado el 18 de agosto de 2013 .

Enlaces externos