ejecutar compilar como archivo c++ c compiler-construction migration language-interoperability

como - ¿Qué problemas puedo esperar al compilar el código C con un compilador de C++?



compilar y ejecutar c en windows (8)

Si toma una base de código C existente y la compila con un compilador C ++, ¿qué tipo de problemas puede esperar que surjan? Por ejemplo, creo que asignar un entero a un valor con un tipo enumerado fallará en C ++, mientras que es legal (si es un poco desagradable) en C.

Si no envuelvo todos mis archivos C en extern C { ... } , ¿voy a cambiar de nombre donde menos lo espero? ¿Hay alguna razón por la que realmente no debería hacer esto?

Para el fondo, tenemos una gran base de código escrita en C. Durante algunos años hemos estado saltando a través de aros para hacer cosas que vendrían naturalmente a través de C ++ (herencia homebrewe, por ejemplo). Nos gustaría comenzar a avanzar hacia C ++, pero de forma gradual; obtener nuestro marco similar al de CORBA para soportarlo, y refaccionar los módulos a medida que avanzamos para aprovechar el enfoque más natural que C ++ proporcionaría.


C ++ tiene una comprobación de tipos más estricta, por lo que es posible que deba agregar un molde a cada llamada a malloc / realloc / calloc.


Consulte Incompatibilidades entre ISO C y ISO C ++ para obtener una lista muy detallada de todas las incompatibilidades. Hay muchos problemas sutiles, incluidos algunos que no se manifiestan inmediatamente en un error de compilación. Por ejemplo, un problema que puede ser un problema es el tamaño de las constantes de los caracteres:

// In C, prints 4. In C++, prints 1 printf("%d/n", sizeof(''A''));


En general, no tendrás ningún problema en absoluto. Sí, hay algunas incompatibilidades entre C y C ++, pero no parecen surgir con tanta frecuencia a excepción del malloc casting mencionado anteriormente, que es bastante trivial de arreglar.

He compilado y utilizado con éxito las siguientes bibliotecas C de código abierto como C ++:

  • el analizador Expat XML
  • el rasterizador de fuentes FreeType2
  • libjpeg: maneja imágenes JPEG
  • libpng: maneja imágenes PNG
  • la biblioteca de compresión Zlib

La parte más difícil fue agregar contenedores de espacio de nombres, lo que llevó algunas horas, en gran parte debido a las declaraciones #include enterradas profundamente en el código, que tenía que estar fuera del espacio de nombres C ++.

¿Por qué hice esto? Porque vendo una biblioteca comercial que las personas estaban vinculando directamente en sus aplicaciones; y a veces sus aplicaciones estaban vinculadas a otras versiones de Expat, FreeType, etc. Esto causó errores de símbolo definido de forma múltiple. Lo más limpio que podía hacer era mover todo dentro de mi biblioteca y esconderlo en mi espacio de nombres.

Sin embargo, no hice eso con todas las bibliotecas de código abierto que uso. Algunos todavía no han provocado conflictos, y no he podido solucionarlos, lo cual, aunque sin problemas, es bastante tedioso. La excepción interesante es SQLite, que no pude compilar en C ++. Así que hice una búsqueda masiva y reemplazo, agregando un prefijo (el nombre de mi producto) a cada símbolo visible externamente. Eso resolvió el problema de mi cliente.


He hecho algo así una vez. La principal fuente de problemas fue que C ++ es más estricto con los tipos, como sospechabas. Tendrá que agregar moldes donde void * se mezclan con punteros de otros tipos. Como asignando memoria:

Foo *foo; foo = malloc(sizeof(*foo));

Lo anterior es un código C típico, pero necesitará un molde en C ++:

Foo *foo; foo = (Foo*)malloc(sizeof(*foo));

Hay nuevas palabras reservadas en C ++, como "clase", "y", "bool", "captura", "eliminar", "explícito", "mutable", "espacio de nombres", "nuevo", "operador", "o", "privado", "protegido", "amigo", etc. No se pueden usar como nombres de variables, por ejemplo.

Los anteriores son probablemente los problemas más comunes cuando compila código C antiguo con un compilador C ++. Para obtener una lista completa de incompatibilidades, consulte Incompatibilidades entre ISO C y ISO C ++ .

También preguntas sobre el cambio de nombre. En ausencia de envoltorios "C" externos, el compilador C ++ destruirá los símbolos. No es un problema siempre que use solo un compilador de C ++, y no confíe en dlsym () o algo así para extraer símbolos de las bibliotecas.


Intenta compilar con un compilador C ++:

typedef enum{ false = 0, true = 1} bool;


Lo he hecho antes de usar MSVC; si usa MSVC, una buena estrategia es:

  1. Establezca archivos individuales para compilarlos como CPP, de esa forma puede pasar gradualmente a un compilador CPP.
  2. Trabaje a través de archivo por archivo usando ctrl + f7 solo para compilar ese archivo.
  3. En lugar de convertir todos los mallocs, puede crear una versión de plantilla en su lugar

foo = (Foo *) malloc (sizeof (* foo));

se convierte

foo = malloc<Foo>();

Y, por supuesto, puede tener una sobrecarga para los casos en los que desea un Foo + n bytes

También recomendaría cambiar las asignaciones de memoria para usar RAII siempre que sea posible, encontré que algunas funciones eran bastante complejas, por lo que cambiar a RAII era demasiado alto, en la mayoría de los casos fue lo suficientemente simple de hacer.


Otro ejemplo: no hay una conversión implícita de Ints a Enums en C ++, mientras que hay uno en C. Necesitarás un elenco si realmente quieres hacerlo en C ++.


Si no envuelvo todos mis archivos C en "Extern C {...}", ¿tendré que cambiar el nombre donde menos lo espero?

Te muerde cuando intentas unir C y C ++.

He escrito muchos archivos de encabezado que contienen:

#ifdef __cplusplus extern "C" { #endif // rest of file #ifdef __cplusplus } #endif

Después de un tiempo se fusiona con el texto repetitivo de incluir múltiples y deja de verlo. Pero debes tener cuidado donde lo pones, generalmente pertenece después de que cualquier incluye tu encabezado.

¿Hay alguna razón por la que realmente no debería hacer esto?

Si está seguro de que no combinará C y C ++, entonces no hay razón para hacerlo que yo sepa. Pero con la migración gradual que describes, es esencial para cualquier cosa con una interfaz publicada que los componentes C y los componentes C ++ necesiten usar.

La gran razón para no hacerlo es que le impide sobrecargar funciones (al menos en esos encabezados). Es posible que desee hacer eso una vez que haya migrado todo su código a C ++ y haya comenzado a mantenerlo / refactorizarlo / ampliarlo.