40 años de amor y odio entre C y C ++

Autor | cor3ntin

Traductor | Luna creciente, Editor a cargo | Zheng Liyuan

Imagen de la cabeza | Descarga de CSDN de Visual China

Exposición | CSDN (ID: CSDNnews)

La siguiente es la traducción:

A principios de la década de 1970, Bell Labs creó el lenguaje C, que fue un subproducto del desarrollo de UNIX. Pronto C se convirtió en uno de los lenguajes de programación más populares. Pero para Bjarne Stroustrup, el poder expresivo de C no es suficiente. Así que amplió el lenguaje C en su tesis doctoral en 1983.

Así nacieron las clases de apoyo a la lengua C.

En ese momento, Bjarne Stroustrup entendió que los lenguajes de programación tenían muchos componentes, además del lenguaje en sí, había compiladores, enlazadores y varias bibliotecas. Proporcionar herramientas familiares ayuda a que el idioma sea ampliamente aceptado. En este contexto histórico, tiene sentido desarrollar C ++ sobre la base del lenguaje C.

40 años después, tanto C como C ++ se han utilizado ampliamente en la industria. Sin embargo, los desarrolladores de C en Internet creen que C ++ es el peor invento humano de la historia, y muchos desarrolladores de C ++ esperan que algún día el lenguaje C desaparezca.

¿Qué diablos pasó?

En la superficie, tanto C como C ++ pueden satisfacer el mismo caso de uso: código de alto rendimiento, determinista, nativo pero portátil, que se puede utilizar en la más amplia gama de hardware y aplicaciones.

Sin embargo, lo que enorgullece más a C es que es un lenguaje de bajo nivel, más cercano al ensamblaje.

Y C ++, desde el primer día de su nacimiento, estuvo lleno de todo tipo de cosas extrañas. Por ejemplo, la magia negra del destructor. Compilador de autoafirmación. Aunque C ++ tenía capacidades de inferencia de tipos desde el principio, los desarrolladores a mediados de la década de 1980 no podían aceptar este concepto, por lo que Bjarne Stroustrup tuvo que eliminar auto hasta que se volviera a agregar C ++ 11.

Desde entonces, C ++ ha seguido agregando varias herramientas para lograr la abstracción. Es difícil decir si C ++ es un lenguaje de bajo nivel o un lenguaje de alto nivel. Para propósitos de diseño, C ++ es ambos. Pero es difícil establecer abstracciones de alto nivel sin sacrificar el rendimiento. Entonces C ++ introdujo varias herramientas para implementar constexpr, mover semántica, plantillas y la biblioteca estándar en constante crecimiento.

Básicamente, creo que C confía en los desarrolladores y C ++ confía en los compiladores. Esta es una gran diferencia, que no se puede ocultar con una simple coherencia como "los tipos originales de los dos son iguales" y "la sintaxis del ciclo while es la misma".

Los desarrolladores de C ++ culpan a C por estos problemas, mientras que los desarrolladores de C piensan que C ++ es demasiado loco. Creo que esta afirmación también es correcta cuando se mira C ++ desde la perspectiva de C. Como superconjunto de C, C ++ es realmente una locura. Un desarrollador de C experimentado puede no estar familiarizado con C ++. C ++ no es C, lo que es suficiente para provocar un acalorado debate en Internet.

Sin embargo, aunque no me gusta C, no tengo derecho a burlarme de C. Aunque tengo algo de experiencia en C ++, el código escrito en C es muy raro y debe ser un código muy malo. Un buen lenguaje de programación incluye buenas prácticas, patrones y modismos, todos los cuales requieren años de aprendizaje. Si intenta escribir código C en C ++, o escribir código C ++ en C, debe sentirse mal. Incluso si conoce C, no necesariamente sabe C ++, y viceversa, no necesariamente sabe programación en C si conoce C ++.

Entonces, ¿deberíamos dejar de hablar de C / C ++ y sentirnos tristes por estos dos nombres desafortunados? No tanto.

Aunque la filosofía de diseño de C ++ es diferente de C, C ++ sigue siendo un superconjunto de C. En otras palabras, puede incluir archivos de encabezado C en la unidad de conversión C ++, para que aún se pueda compilar. Y aquí es donde se produce el caos.

C ++ no es una extensión de C. Es un estándar diseñado de forma independiente por diferentes comités y diferentes personas. Lógicamente hablando, las personas a las que les gustan las ideas de C ++ participarán en la comunidad de C ++ y en el proceso de estandarización de C ++, mientras que otros podrán intentar participar en C. Ya sea un comité C o un comité C ++, la forma en que expresan su intención y dirección solo puede ser a través de su producto final: el estándar; y el estándar es el resultado de muchos votos.

Sin embargo, es difícil para el compilador saber si se trata de archivos de encabezado C o archivos de encabezado C ++.

La marca "C" externa no se ha utilizado de manera generalizada y solo puede afectar la modificación, no la sintaxis o la semántica. El archivo de encabezado solo afecta al preprocesador. Para el compilador de C ++, todo es una unidad de conversión de C ++, entonces es C ++. Sin embargo, la gente todavía incluye archivos de encabezado C en C ++ y espera que "simplemente funcione", y funciona la mayor parte del tiempo.

Entonces, no podemos evitar preguntar:

¿Cómo puede el código C ++ desarrollado por diferentes personas en diferentes lugares mantener la compatibilidad con C?

Me temo que será difícil.

Recientemente, un colega me recordó la Ley de Conway:

"La arquitectura del sistema de diseño está limitada por la estructura de comunicación de la organización que produjo estos diseños".

Según esta lógica, si dos miembros del comité no cooperan entre sí, los lenguajes que crean no se comunicarán.

C ++ mantiene una lista de incompatibilidades con C y su biblioteca estándar. Sin embargo, la lista no parece reflejar muchas de las funciones agregadas en C11 y C18 que no son legales en C ++. Para una introducción más clara, consulte esta página de Wikipedia (https://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B).

Sin embargo, enumerar la incompatibilidad entre los dos idiomas no es suficiente para medir la incompatibilidad entre los dos.

Esas funciones que existen en la biblioteca estándar de C ++ pero que se declaran principalmente desde C son difíciles de declarar como constexpr, y aún más difíciles de declarar como noexcept. La compatibilidad con C generará costos de rendimiento y las funciones C son un obstáculo para la optimización.

Muchas estructuras C son válidas en C ++, pero no pueden pasar la revisión de código (como NULL, longjmp, malloc, constructor / destructor, free, coerción de tipo de estilo C, etc.).

En C, estos modismos pueden no ser un gran problema, pero no están en C ++. C ++ tiene un sistema de tipos más potente. Desafortunadamente, el lenguaje de C ha hecho un hueco en este sistema de tipos, por lo que lograr la compatibilidad con C requiere un precio en términos de seguridad.

No me malinterpretes, C ++ todavía se preocupa por la compatibilidad con C, hasta cierto punto. Sin embargo, es interesante que C también se preocupe por C ++, hasta cierto punto. Para ser honesto, C se preocupa por C ++ más de lo que C ++ se preocupa por C. Parece que cada comité todavía se preocupa por el trabajo del otro comité. Pero somos muy reacios.

C ++ sabe que muchas bibliotecas básicas están escritas en C, incluidas no solo libc, sino también zip, png, curl, openssl (!) Y muchas otras bibliotecas, que son utilizadas por innumerables proyectos de C ++. C ++ no puede romper esta compatibilidad.

Pero recientemente, especialmente en los últimos diez años, la escala de C ++ ha superado con creces a C. C ++ tiene más usuarios y la comunidad es más activa. Quizás es por eso que el comité de C ++ es ahora más de 10 veces más grande que el comité de C.

C ++ es una fuerza que no se puede ignorar, por lo que el comité de C debe considerar no romper la compatibilidad con C ++. Si uno tiene que decir que un estándar sigue a otro estándar, entonces C ++ es ahora el líder y C es el seguidor.

Ahora, C ++ está en un ciclo estable de tres años, ya sea con viento, lluvia, sol abrasador o una nueva epidemia fatal. Y C solo lanza una versión principal cada diez años aproximadamente. Pero esto también es razonable, porque como lenguaje de nivel inferior, C no necesita desarrollarse tan rápido.

El entorno del lenguaje C también es completamente diferente al de C ++. C se usa principalmente para plataformas y más para compiladores. Todos (incluso su perro) pueden escribir un compilador de C, porque el conjunto de características del lenguaje es pequeño, por lo que cualquiera puede escribir un compilador de C. Solo hay cuatro implementaciones realmente consideradas por el comité de C ++, y estas cuatro implementaciones aparecerán en cada reunión. Por lo tanto, muchas funciones en el lenguaje C están relacionadas con la implementación o son soporte opcional, por lo que varios compiladores pueden afirmar que han cumplido con el estándar sin demasiado esfuerzo Se dice que los miembros del comité estarán más contentos.

Actualmente, C ++ se centra más en la portabilidad que en la libertad de implementación. Ésta es otra diferencia en filosofía.

Por lo tanto, su propuesta rompe la compatibilidad de C

Parte del P2178 que propuse afectará teóricamente la compatibilidad con C. En este caso, no todas las soluciones serán satisfactorias.

Alguien podría decirle que primero puede proponer sus nuevas funciones al comité C. Esto significa que es necesario realizar más reuniones. Las estrictas reglas de asistencia de la reunión C pueden impedirle asistir a la reunión, lo que impide que las personas que no estén dispuestas a gastar miles de dólares se conviertan en miembros de ISO. Esto se debe a que el Comité C debe cumplir con las normas ISO.

Además, si se acaba de publicar la nueva norma, es posible que pasen diez años hasta que se considere su propuesta. Más importante aún, si el Comité C no comprende o no se preocupa por el problema que está tratando de resolver, entonces su propuesta caerá en la nada. O puede que no tengan la energía para lidiar con este problema. Además, es posible que no tenga la energía para lidiar con C. Después de todo, su intención es mejorar C ++. De hecho, incluso si nadie objetó su propuesta en la reunión (aunque es poco probable que suceda), si alguien le pide que lo discuta primero con el comité C, será condenado a muerte por su propuesta.

Otra posibilidad es que el comité de C acepte una versión ligeramente diferente de la versión que existe en C ++. Verdadero solo se puede lograr haciendo una macro. char16_t necesita pasar typedef. char32_t no es necesariamente UTF-32. static_assert corresponde a _Static_assert.

Hay muchos casos así, ¿deberíamos culpar a C? Probablemente no. Su comité solo está tratando de mejorar el lenguaje C. viceversa. En C ++ 20, el inicializador especificado está inspirado en C, pero se adopta una regla ligeramente diferente, porque si son exactamente iguales, no cumplen con las reglas de inicialización de C ++.

También soy responsable de este problema. C tiene VLA. Si estuviera allí en ese momento, definitivamente me opondría a adoptarlo en C ++ estándar, porque causó demasiados problemas de seguridad. También me opondré firmemente a la propuesta de agregar _Generic a C ++. Quizás el propósito de _Generic sea reducir los problemas causados ​​por la falta de plantillas o la falta de sobrecarga, pero C ++ tiene estas dos funciones. Desde mi punto de vista, _Generic no es adecuado para C ++ como imaginaba.

Los dos comités parecen tener diferentes niveles de interés en el idioma del otro. A veces tenemos muy buena compatibilidad (std :: complex) y, a veces, no nos importa la compatibilidad (parámetros de matriz estática).

No hay forma. No olvide que cada comité es un grupo de personas que votan en diferentes momentos y lugares, y tratar de controlar los resultados hará que la votación no tenga sentido. No es realista poner a estas personas en la misma habitación. ISO puede oponerse y el desequilibrio de los participantes hará que la gente de C esté en gran desventaja.

La compatibilidad con C no es importante

Si es un desarrollador de C, definitivamente considerará a C como un lenguaje de programación conciso. Pero para el resto de nosotros, C tiene una impresión completamente diferente.

C es un pegamento universal en varios idiomas que puede unir todo firmemente.

Para los usuarios de C ++, C es su API. Desde este punto de vista, el valor de C radica en su sencillez. Recuerde, la parte de C que le importa a C ++ es la C que aparece en la interfaz (archivo de encabezado). Nos preocupan las declaraciones, no las definiciones. C ++ necesita llamar a funciones en la biblioteca C (lo mismo ocurre con lenguajes como Python, Fortran, Rust, D, Java, etc., en todos los casos, C puede usarse en el límite de la interfaz).

Por lo tanto, C es un lenguaje de definición de interfaz. Cuanto más contenido se agrega a C, más difícil es definir la interfaz. Es menos probable que estas interfaces se mantengan estables con el tiempo.

Entonces, ¿es importante la falta de <threads.h> en C ++? Puede que no sea importante porque es poco probable que aparezca en la interfaz pública.

Ahora todo el mundo habla de C

En el pasado, la compatibilidad con C era un gran punto de venta de C ++. Pero ahora, todos (incluso sus peces de colores) entienden C. Rust puede llamar a funciones C, Python, Java, ¡y todos los lenguajes pueden! Incluso un Javascript extraño puede llamar a funciones C en WebAssemby.

Pero en estos lenguajes, la interfaz es explícita. Las herramientas proporcionadas por el lenguaje pueden exponer declaraciones C específicas. Por supuesto, esto es más problemático. Pero esto puede hacer que la interfaz sea muy, muy clara. Y todavía está limitado. Por ejemplo, en rust, llamar a funciones C no obliga a Rust a sacrificar algún diseño para acomodar el subconjunto C. De hecho, C está incluido.

mod confinment {


    use std::os::raw::{c_char};


    extern "C" {


        pub fn puts(txt: *const c_char);


    }


 


}


 


pub fn main() {


    unsafe {


        confinment::puts(


            std::ffi::CString::new("Hello, world!").expect("failed!").as_ptr()


        );


    }


}

Explorador del compilador

A menos que cambie la ABI de C, este código siempre se puede ejecutar normalmente. Y el límite Rust / C es muy claro y se explica por sí mismo.

Por lo tanto, C ++ es probablemente el lenguaje que más paga por la compatibilidad con C.

Para empeorar las cosas, abra cualquier archivo de encabezado C y pronto encontrará un montón de #ifdef __cplusplus. Sí, la compatibilidad con C ++ a menudo requiere mucho trabajo por parte de los desarrolladores de C. La compatibilidad siempre ha sido un espejismo. Mucha gente conoce este tweet mío:

¿Dónde debemos ir?

Creo que ambos comités están tratando de comunicarse más. Planean celebrar una reunión en Portland el próximo año (aunque este plan puede cambiar). La comunicación es algo bueno.

Pero el efecto de la comunicación entre pollo y pato será muy limitado. Es posible que los pilares de diseño de los dos idiomas no estén coordinados. Intentaré sugerir una plantilla. Pero primero tengo que quejarme de que el lenguaje C no tiene módulos, ni espacios de nombres, y qué es toda la macro.

¿Quizás el subconjunto de C que C ++ puede aceptar puede restringirse a C99? ¿Quizás ambos lenguajes necesitan encontrar un subconjunto común y desarrollarse de forma independiente? Quizás extern C necesite afectar el análisis. Si C ++ ha pasado por varias eras, entonces C puede ser una de ellas.

Quizás necesitemos aceptar C como un subconjunto de C ++, pero la única forma es incorporar WG14 en WG21.

Es posible que el status quo no cambie. Es posible que C ++ nunca esté libre de sus orígenes, y es posible que C siempre tenga que luchar contra las características sucias del lenguaje C.

Original: https://cor3ntin.github.io/posts/c/

 Este artículo es una traducción de CSDN, indique la fuente de la reimpresión.


更多精彩推荐
☞谷歌软件工程师薪资百万,大厂薪资有多高?
☞CSDN 创始人蒋涛:选择长沙作“大本营”,打造开发者中心城市
☞杜甫在线演唱《奇迹再现》、兵马俑真人还原……用AI技术打破次元壁的大谷来参加腾讯全球数字生态大会啦!
☞开放源码,华为鸿蒙HarmonyOS 2.0来了
☞20张图,带你搞懂高并发中的线程与线程池!
☞跨链,该怎么跨?
点分享点点赞点在看

Supongo que te gusta

Origin blog.csdn.net/csdnnews/article/details/108557600
Recomendado
Clasificación