oficial - Estándares de codificación C y C++
iso iec 14882 (6)
C ++ no hace ''tipos de cheques seguros'' en tiempo de ejecución a menos que los solicite (usando dynamic_cast
). C ++ es altamente compatible con C, por lo que puede llamar libremente a las bibliotecas C como desee y compilar el código C con un compilador C ++. C ++ no implica ''orientado a objetos'', y no debería obtener ninguna penalización de rendimiento por su uso.
Si mezcla el código compilado con gcc y con g ++, consulte la respuesta de Graeme.
¿Cuáles son las mejores prácticas con respecto a los estándares de codificación C y C ++? ¿Se les debe permitir a los desarrolladores mezclarlos de todos modos? ¿Hay alguna complicación al vincular archivos de objeto C y C ++?
¿Deberían las cosas como las bibliotecas de sockets que tradicionalmente están escritas en C permanecer en C y guardarse en archivos de origen separados? Eso es mantener código c en archivos .c y código c ++ en archivos .cpp. Cuando se mezclan c y C ++ después de analizarse con g ++, ¿habrá alguna penalización en el rendimiento, ya que las comprobaciones de tipo seguro no se realizan en C? pero están en C ++. Sería la mejor manera de vincular los archivos de código fuente de C y C ++.
No hay buenas reglas duras y rápidas aquí.
Si el producto final siempre estará vinculado con un C ++ main () entonces realmente no importa. Como siempre puedes crear encabezados que harán lo correcto.
Si está creando una biblioteca que necesita tener una interfaz C y C ++, pero no puede suponer el enlazador C ++, entonces deberá asegurarse de separar la API C de C ++ limpiamente. En este punto, generalmente es más limpio hacer todo el trabajo en C y usar clases de C ++ para representar a la C.
Por ejemplo:
/* c header */
struct CData
{ /* stuff */ };
void init( CData* data );
void fini( CData* data );
int getSomething( CData* data );
void doSomething( CData* data, int val );
// c++ header
extern "C" {
#include cdata.h
};
class CppData : private CData
{
public:
CppData() { ::init( (CData*)this ); }
~CppData() { ::fini( (CData*)this ); }
int getSomething() { return ::getSomething( (CData*)this ); }
void doSomething( int val ) { :: doSomething( (CData*)this, val ); }
};
Espero que esto ayude.
Si compila toda su fuente con g ++, entonces todo se compila en archivos de objeto C ++ (es decir, con el nombre adecuado de manipulación y el C ++ ABI).
Solo necesitará usar el truco externo "C" si está creando librerías que necesitan ser usadas por aplicaciones C explícitamente que necesitan usar el C ABI.
Si todo se está compilando en un único ejecutable, utilice g ++ y trate todo como C ++
Si tiene una función en C ++ que llama a una función en C que a su vez llama a otra función en C ++, y esta función posterior arroja una excepción que debería capturarse con la primera función, puede tener problemas a menos que le indique al compilador de C que habilite generación de tablas de manejo de excepciones.
Para gcc, este es el parámetro -fexceptions
, que está habilitado de manera predeterminada para C ++ pero deshabilitado por defecto para C.
El mayor problema es llamar a una función C desde el código C ++ o viceversa. En ese caso, debe asegurarse de marcar la función como si tuviera una vinculación "C" usando extern "C"
. Puede hacer esto en el archivo de encabezado directamente usando:
#if defined( __cplusplus )
extern "C" {
#endif
extern int myfunc( const char *param, int another_one );
#if defined( __cplusplus )
}
#endif
Necesita el #if
s porque el código C que lo incluye no comprenderá la extern "C"
.
Si no desea (o no puede) cambiar el archivo de encabezado, puede hacerlo en el código de C ++:
extern "C" {
#include "myfuncheader.h"
}
Puede marcar una función C ++ como si tuviera una vinculación C de la misma manera, y luego puede llamarla desde el código C. No puede hacer esto para funciones sobrecargadas o clases C ++.
Aparte de eso, no debería haber problemas para mezclar C y C ++. Tenemos varias funciones C de hace décadas que todavía están siendo utilizadas por nuestro código C ++.
En general, se debe asumir que c ++ puede arrojar excepciones, por lo tanto, las funciones de la envoltura C en su bloque deben atraparlas y transformarlas en buenos códigos de error que la persona que llama puede digerir.
extern "c"
{
int nice_c_function_interface
(
void
)
{
int returnStatus;
try
{
returnStatus = nice_cpp_function();
}
catch (NiceCppException& that)
{
returnStatus = that.failure_code();
}
catch (...)
{
cerr << "Oh Worse! an unexpected unknown exception" << endl;
returnStatus = -1; // Horrible unknown failure
}
return returnStatus;
}
}