Recientemente me preguntaba cuándo usar C sobre C ++, y viceversa. Afortunadamente, alguien ya me ganó y, aunque me llevó un tiempo, pude digerir todas las respuestas y comentarios a esa pregunta.
Sin embargo, un elemento en esa publicación sigue siendo abordado una y otra vez, sin ningún tipo de ejemplo, verificación o explicación:
"El código C es bueno para cuando quieres tener enlaces de múltiples idiomas para tu biblioteca"
Eso es una paráfrasis. Debo señalar que varias personas señalan que los enlaces de múltiples idiomas son posibles en C ++ (a través de algún extern
funcionamiento), pero sin embargo, si lees esa publicación en su totalidad, es bastante obvio que C es ideal para la portabilidad / enlace de lenguaje. Mi pregunta es: ¿por qué?
¿Alguien puede proporcionar razones concretas por las que escribir bibliotecas en C permite enlaces y / o portabilidad más fáciles en otros idiomas?
Respuestas:
C tiene una interfaz mucho, mucho más simple, y sus reglas para convertir una interfaz de código fuente en una interfaz binaria son tan sencillas que la generación de interfaces externas para enlazar se realiza de una manera bien establecida. C ++, por otro lado, tiene una interfaz increíblemente complicada, y las reglas para el enlace ABI no están estandarizadas en absoluto, ni formalmente ni en la práctica. Esto significa que casi cualquier compilador para cualquier lenguaje para cualquier plataforma puede unirse a una interfaz C externa y saber exactamente qué esperar, pero para una interfaz C ++, es esencialmente imposible porque las reglas cambian dependiendo de qué compilador, qué versión y qué plataforma con la que se creó el código C ++.
fuente
extern "C"
, aún es más trabajo adicional hacerlo, que debe equilibrarse con las características proporcionadas por C ++)extern "C"
.Si está tratando de comunicarse con un hablante de otro idioma, el pidgin es más fácil que el inglés de Shakespeare.
Los conceptos de C (llamadas de función, punteros, cadenas terminadas en NULL) son muy sencillos, por lo que otros lenguajes pueden implementarlos fácilmente lo suficientemente bien como para llamar a funciones de C. Por razones históricas, se implementan muchos otros lenguajes en C, lo que hace que llamar a las funciones de C sea aún más fácil.
C ++ agrega bastantes cosas: clases, con herencia y vtables y modificadores de acceso; excepciones, con el desbobinado de la pila y el cambio del flujo de control; plantillas. Todo esto dificulta que otros lenguajes usen enlaces de C ++: en el mejor de los casos, hay más "pegamento" o código de interoperabilidad para implementar, y en el peor de los casos, los conceptos no se traducen directamente (debido a diferencias en los modelos de clase, manejo de excepciones, etc.) Para las plantillas en particular, simplemente usarlas (crear instancias) generalmente requiere un paso de compilación con un compilador de C ++, lo que complica enormemente su uso desde otros entornos.
Dicho todo esto, es posible exagerar la dificultad de proporcionar enlaces desde una biblioteca C ++ a otro idioma:
extern "C"
, por lo que puede exportar enlaces de lenguaje de estilo C (con toda la simplicidad y compatibilidad de enlaces de C) desde una biblioteca de C ++ (con la limitación de que no puede exponer ninguna funcionalidad específica de C ++) .fuente
C es uno de los idiomas más antiguos que existen. Su ABI es simple, y prácticamente todos los sistemas operativos que todavía se usan hoy en día se han escrito en él . Si bien algunos de esos sistemas operativos pueden haber agregado cosas, por ejemplo, en C # / .NET o lo que sea en la parte superior, a continuación están muy inmersos en C.
Eso significa que, para utilizar la funcionalidad proporcionada por el sistema operativo, prácticamente todos los lenguajes de programación necesitan una forma de interactuar con las bibliotecas C de todos modos . Perl, Java, C ++, todos de forma nativa proporcionan formas de "hablar C", porque tenían que hacerlo si no querían reinventar cada rueda que hay.
Esto hace que C sea el latín de los lenguajes de programación. (¿Cuántos años de internet antes de esa metáfora tiene que ser "el inglés de los lenguajes de programación"?)
Cuando escribe su biblioteca en C, obtiene una interfaz compatible con C de forma gratuita (obviamente). Si está escribiendo su biblioteca en C ++, puede obtener enlaces C, a través de
extern "C"
declaraciones como usted mencionó.Sin embargo , se puede conseguir esas fijaciones solamente para la funcionalidad que puede ser expresado en C .
Por lo tanto, su API de biblioteca no puede hacer uso de ...
Un ejemplo simple, necesitaría hacer que sus funciones exportadas tomen y devuelvan matrices (
[]
) en lugar destd::vector
(ostd::string
para el caso).Por lo tanto, no solo no podrá proporcionar ninguna de las cosas buenas que C ++ tiene para ofrecer a los clientes de su biblioteca, sino que también tendrá que hacer un esfuerzo adicional para "traducir" la API de su biblioteca de C ++ a "C compatible" (
extern "C"
).Es por eso que se puede señalar que C es la mejor opción para implementar una biblioteca. Personalmente, creo que los beneficios de C ++ aún superan el esfuerzo necesario para una
extern "C"
API, pero solo soy yo.fuente
Dejando de lado los detalles que otras respuestas ya proporcionan:
La razón por la que tantos lenguajes proporcionan un enlace C es que todos los sistemas operativos * nix y Windows exponen la mayor parte de su API del sistema operativo a través de una interfaz C. Por lo tanto, la implementación del lenguaje ya necesita interactuar con C para poder ejecutarse en los Oses principales. Por lo tanto, es sencillo ofrecer también comunicarse directamente con cualquier interfaz C desde el lenguaje mismo.
fuente
No hay razón. Si la semántica que intenta expresar es fundamentalmente compatible con C y no es algo así como plantillas, no hay ninguna razón por la que pueda vincular más fácilmente si la implementación está escrita en C. De hecho, es prácticamente por definición que una interfaz C puede ser completado por cualquier implementación que pueda cumplir con el contrato binario, incluida una implementación en otro idioma. Hay lenguajes distintos de C ++ que pueden implementar contratos binarios en C que pueden funcionar de esta manera.
Lo que realmente se reduce a personas que no quieren aprender nuevos idiomas o ideas que tengan semánticas o características realmente útiles que intentan desesperadamente elegir cualquier motivo para permanecer en la era de los dinosaurios.
fuente
Hay dos ejes principales al interactuar con otro idioma:
C tiene una ventaja sobre C ++ en esos dos frentes:
Ahora, ¿por qué la mayoría de los lenguajes tienen un conjunto de conceptos similar al de C? Puede deberse a que sea "simple" o "preexistente"; sin embargo, no importa, lo importante es que sí.
Por el contrario, C ++ tiene conceptos complejos, y cada compilador decide el ABI (aunque muchos se adhieren al Itanimum ABI, excepto en Windows ...). En realidad, Herb Sutter propuso que los sistemas operativos solucionen un ABI de C ++ (según el sistema operativo) para abordar parcialmente este problema. Además, se debe tener en cuenta que es posible un FFI C ++, D lo está intentando 3 .
1 Excepto las variables (
...
), esas no son simples2 ¿C tiene un ABI estándar?
3 Interfaz de D a código heredado de C ++
fuente
Básicamente se trata de la estandarización ABI. Si bien ni C ni C ++ tienen un ABI estandarizado que otros lenguajes pueden usar para interactuar entre los binarios escritos, C se ha convertido en un estándar de facto, todos lo saben y todos los demás pueden usar las mismas reglas simples que el lenguaje tiene con respecto a tipos y llamadas a funciones.
C ++ podría tener un ABI estándar, pero Stroustrup ha dicho que no ve la necesidad de uno. También dice que sería difícil obtener el consenso de los escritores de compiladores (aunque dudo que: el comité estándar de C ++ emitiría un ABI similar a los existentes y los escritores de compiladores simplemente alterarían la próxima versión de sus compiladores, que en ocasiones son incompatibles con los binarios construido con versiones antiguas de sus compiladores de todos modos: recuerdo haber recompilado un par de bibliotecas con un nuevo compilador de Sun y descubrí que no funcionaban con las antiguas)
Notarás que algunas compañías se han movido a usar un ABI estándar, Microsoft comenzó este proceso con COM en los años 90, y hoy lo han refinado en WinRT ABI (que no debe confundirse con el otro WinRT que se refiere a un tipo de sistema operativo de tabla) que permite que los programas escritos en C # se comuniquen con las bibliotecas escritas en C o C ++ (es decir, la capa del sistema operativo de Microsoft está escrita en C ++, expuesta usando WinRT y consumida por aplicaciones C # cuando llaman a cualquier rutina de tiempo de ejecución del sistema operativo)
No hay mucho que nadie pueda hacer a menos que un organismo de normalización intensifique y solucione esta situación. Microsoft obviamente ve el valor en él y ha tomado medidas para resolverlo para su plataforma.
Entonces la respuesta es realmente C no proporciona enlaces de lenguaje. Sucede que nadie los ha escuchado y los consume independientemente.
fuente
Todas las respuestas no alcanzan el problema real: la compilación de C ++ introduce "cambio de nombre", por lo que los binarios son incompatibles con las llamadas de función "simples".
Todo lo de ABI es poco más que un intento de estandarizarlo.
En general, no está garantizado que pueda vincular funciones compiladas con diferentes compiladores, incluso si se apega a C ++ simple. Antes era seguro que eran incompatibles, pero hoy en día la estandarización se está arrastrando;)
OTOH C fue diseñado precisamente para ser un "ensamblaje de alto nivel" y permitir todo tipo de interfaz fácil. No debería sorprendernos que sea más adecuado para el gusto entre idiomas.
Nota al margen: el compilador C ++ original (cfront) en realidad produjo una fuente C que tuvo que ser compilada, exactamente como gcc que produce el ensamblaje "bajo el capó".
fuente