¿Por qué las personas usan C si es tan peligroso?

132

Estoy considerando aprender C.

Pero, ¿por qué las personas usan C (o C ++) si se puede usar 'peligrosamente'?

Por peligroso, quiero decir con punteros y otras cosas similares.

Como la pregunta de desbordamiento de pila ¿ Por qué la función gets es tan peligrosa que no debería usarse? . ¿Por qué los programadores no solo usan Java o Python u otro lenguaje compilado como Visual Basic?

Tristan
fuente
152
¿Por qué los chefs usan cuchillos, si se pueden usar 'peligrosamente'?
Oerkelens
78
Con un gran poder viene una gran responsabilidad.
Pieter B
10
Joe Blow, pontifica mucho?
Matthew James Briggs
44
Porque "Back In The Day" cuando C se convirtió en el lenguaje de elección, se esperaba que pudiéramos manejar cosas como esa, porque teníamos que hacerlo. Los lenguajes interpretados o codificados por bytes eran demasiado lentos porque los procesadores del día eran mucho más lentos. (Hoy puedo comprar una PC de escritorio de gama baja con una CPU multinúcleo de 2+ GHz y 4 GB de memoria de Dell por $ 279. No tienes IDEA de lo absolutamente increíble que esto le parece a un tipo como yo para quien una PC de 4 MHz con 640 kilobytes de memoria fue felicidad ...). Acéptelo - ganó la Ley de Moore. Juego. ¡Terminado!
Bob Jarvis
66
@Bob Jarvis: el juego no ha terminado. Si cree que su PC de 2 + GHz, 4GB, o su conjunto de varios cientos de PC de 4 GHz con las últimas GPU CUDA, o lo que sea, es lo suficientemente rápido, simplemente no está trabajando en problemas lo suficientemente difíciles :-)
jamesqf

Respuestas:

246
  1. C es anterior a muchos de los otros idiomas en los que está pensando. Mucho de lo que ahora sabemos sobre cómo hacer que la programación sea "más segura" proviene de la experiencia con lenguajes como C.

  2. Muchos de los lenguajes más seguros que han surgido desde C dependen de un tiempo de ejecución mayor, un conjunto de características más complicado y / o una máquina virtual para lograr sus objetivos. Como resultado, C se ha mantenido como un "mínimo común denominador" entre todos los lenguajes populares / convencionales.

    • C es un lenguaje mucho más fácil de implementar porque es relativamente pequeño y tiene más probabilidades de funcionar adecuadamente incluso en el entorno más débil, por lo que es más probable que muchos sistemas integrados que necesitan desarrollar sus propios compiladores y otras herramientas puedan proporcionar un compilador funcional para C.

    • Debido a que C es tan pequeño y tan simple, otros lenguajes de programación tienden a comunicarse entre sí mediante una API tipo C. Esta es probablemente la razón principal por la que C nunca morirá realmente, incluso si la mayoría de nosotros solo interactuamos con él a través de envoltorios.

  3. Muchos de los lenguajes "más seguros" que intentan mejorar en C y C ++ no intentan ser "lenguajes de sistemas" que le brinden un control casi total sobre el uso de memoria y el comportamiento de tiempo de ejecución de su programa. Si bien es cierto que cada vez más aplicaciones simplemente no necesitan ese nivel de control, siempre habrá un pequeño puñado de casos en los que sea necesario (especialmente dentro de las máquinas virtuales y los navegadores que implementan todos estos lenguajes agradables y seguros para el resto de nosotros).

    Hoy en día, hay algunos lenguajes de programación de sistemas (Rust, Nim, D, ...) que son más seguros que C o C ++. Tienen los beneficios de la retrospectiva, y se dan cuenta de que la mayoría de las veces, no se necesita un control tan fino, por lo que ofrecen una interfaz generalmente segura con algunos ganchos / modos inseguros a los que uno puede cambiar cuando sea realmente necesario.

  4. Incluso dentro de C, hemos aprendido muchas reglas y pautas que tienden a reducir drásticamente la cantidad de errores insidiosos que aparecen en la práctica. En general, es imposible obtener el estándar para hacer cumplir estas reglas retroactivamente porque eso rompería demasiado código existente, pero es común usar advertencias del compilador, linters y otras herramientas de análisis estático para detectar este tipo de problemas fácilmente prevenibles. El subconjunto de programas de C que pasan estas herramientas con gran éxito ya es mucho más seguro que "solo C", y cualquier programador de C competente en la actualidad utilizará algunos de ellos.


Además, nunca hará que un concurso de Java ofuscado sea tan entretenido como el concurso de C ofuscado .

Ixrec
fuente
77
El "mínimo común denominador" suena despectivo. Diría que, a diferencia de los muchos lenguajes mucho más pesados, C no impone una tonelada de equipaje adicional que no necesita y le brinda una base ultrarrápida sobre la cual implementar las cosas que necesita. ¿Es eso lo que querías decir?
underscore_d
99
"Realmente no se puede tener uno sin el otro": en realidad, muchos idiomas nuevos (Rust, Nim, D, ...) intentan hacerlo. Esto básicamente se reduce a unir un subconjunto "seguro" del lenguaje con un par de primitivas "inseguras" para cuando este nivel de control es absolutamente necesario. Sin embargo, todos ellos se basan en el conocimiento acumulado de C y C ++, por lo que tal vez debería decirse que en el momento en que se desarrollaron C y C ++, no se podía tener uno sin el otro, y hoy en día hay un lenguaje que intenta dividir sus partes "inseguras", pero aún no se han puesto al día.
Matthieu M.
66
1) no es un punto válido! C tomó características de Algol 68, que es un lenguaje "seguro" en este sentido; entonces los autores sabían sobre tales lenguajes. Los otros puntos son geniales.
reinierpost
44
@MatthieuM. Es posible que también desee ver Microsoft Research. Han producido algunos sistemas operativos administrados en la última década o dos, incluidos algunos que son más rápidos (completamente accidentalmente; el objetivo principal de la mayoría de estos sistemas operativos de investigación es la seguridad, no la velocidad) que un sistema operativo no administrado equivalente para ciertas cargas de trabajo de la vida real . La aceleración se debe principalmente a las restricciones de seguridad: la comprobación de ejecutables estáticos y dinámicos permite optimizaciones que no están disponibles en el código no administrado. Hay bastante que ver, en general, y las fuentes están incluidas;)
Luaan
3
@Luaan: Midori se ve tan increíble; Siempre estoy esperando los artículos del blog de Joe.
Matthieu M.
41

Primero, C es un lenguaje de programación de sistemas. Entonces, por ejemplo, si escribe una máquina virtual Java o un intérprete de Python, necesitará un lenguaje de programación de sistemas para escribirlos.

En segundo lugar, C proporciona un rendimiento que los lenguajes como Java y Python no ofrecen. Por lo general, la informática de alto rendimiento en Java y Python utilizará bibliotecas escritas en un lenguaje de alto rendimiento como C para hacer el trabajo pesado.

Tercero, C tiene una huella mucho menor que lenguajes como Java y Python. Esto lo hace utilizable para sistemas integrados, que pueden no tener los recursos necesarios para soportar los grandes entornos de tiempo de ejecución y las demandas de memoria de lenguajes como Java y Python.


Un "lenguaje de programación de sistemas" es un lenguaje adecuado para construir sistemas de resistencia industrial con; tal como están, Java y Python no son lenguajes de programación de sistemas. "Exactamente lo que hace que un lenguaje de programación de sistemas" esté fuera del alcance de esta pregunta, pero un lenguaje de programación de sistemas necesita proporcionar soporte para trabajar con la plataforma subyacente.

Por otro lado (en respuesta a los comentarios), un lenguaje de programación de sistemas no necesita ser autohospedado. Este problema surgió porque la pregunta original se le preguntó "¿por qué la gente usa C", el primer comentario se le preguntó "¿Por qué necesitaría un lenguaje como C" cuando se tiene PyPy, y señaló que PyPy no en el hecho de utilizar C. Por lo tanto, originalmente era relevante para la pregunta, pero desafortunadamente (y de manera confusa) el "autohospedaje" en realidad no es relevante para esta respuesta. Lo siento, lo mencioné.

En resumen, Java y Python no son adecuados para la programación de sistemas no porque sus implementaciones principales se interpreten o porque las implementaciones compiladas de forma nativa no están autohospedadas, sino porque no brindan el soporte necesario para trabajar con la plataforma subyacente.

tormenta
fuente
19
"Si escribe una máquina virtual Java o un intérprete de Python, necesitará un lenguaje de programación de sistemas para escribirlos". Uh ¿Cómo explicas PyPy? ¿Por qué necesitaría un lenguaje como C para escribir un compilador o un intérprete o una máquina virtual?
Vincent Savard
10
Creo que usted afirmó que necesita un lenguaje de programación del sistema para escribir una máquina virtual Java o un intérprete de Python cuando dijo "si escribe una máquina virtual Java o un intérprete de Python, necesitará un lenguaje de programación del sistema para escribirlos". Si PyPy no lo satisface, también puede buscar cualquier intérprete o compilador escrito en Haskell. O realmente, simplemente agregue una referencia que respalde su reclamo.
Vincent Savard
16
Incluso si se trata de tortugas hasta el fondo, algo como PyPy no podría existir sin un intérprete de Python escrito en otro idioma.
Blrfl
18
@Birfl Pero eso realmente no dice mucho. C no podría haberse escrito sin un compilador de ensamblaje, y no se puede escribir ensamblado sin hardware que lo implemente.
cabeza de jardín
11
Si PyPy no es un "lenguaje de programación de sistemas" porque un compilador de C está involucrado en algún lugar, entonces C tampoco es un lenguaje de programación de sistemas porque un ensamblador se usa en algún lugar. En realidad, ¿no es popular traducir C a algún otro idioma en estos días? por ejemplo, LLVM
30

Lamento agregar otra respuesta, pero no creo que ninguna de las respuestas existentes aborde directamente su primera oración que indique:

'Estoy considerando aprender C'

¿Por qué? ¿Desea hacer el tipo de cosas que C se usa habitualmente en la actualidad (por ejemplo, controladores de dispositivos, máquinas virtuales, motores de juegos, bibliotecas de medios, sistemas integrados, núcleos del sistema operativo)?

En caso afirmativo, entonces sí, seguro aprende C o C ++ dependiendo de los que te interesen. ¿Quieres aprenderlo para tener una comprensión más profunda de lo que está haciendo tu lenguaje de alto nivel?

Luego continúas mencionando las preocupaciones de seguridad. No necesariamente necesita una comprensión profunda de C seguro para hacer esto último, de la misma manera que un ejemplo de código en un lenguaje de nivel superior podría darle la esencia sin estar listo para la producción.

Escriba un código C para obtener la esencia. Luego colóquelo nuevamente en el estante. No se preocupe demasiado por la seguridad a menos que quiera escribir el código C de producción .

Jared Smith
fuente
2
¡Buen trabajo respondiendo lo que parece ser la verdadera pregunta! Una excelente manera de apreciar C / C ++ y los lenguajes "más seguros" por lo que realmente son es intentar escribir algo así como un simple motor de base de datos. Obtendrá una buena idea de cada uno de los enfoques que intente y verá a dónde lo lleva. Verá lo que se siente natural en cualquiera de los dos, y encontrará dónde falla el enfoque natural (por ejemplo, es muy fácil "serializar" datos en bruto en C - ¡solo escriba los datos !; pero el resultado no es portátil, por lo que puede ser de uso limitado). Comprender la seguridad es complicado, porque la mayoría de los problemas pueden ser difíciles de encontrar.
Luaan
1
@Luaan exactamente, aprender a copiar una cadena usando punteros te da la idea, aprender a hacerlo de manera segura es otro nivel, y dependiendo de las metas de uno, quizás innecesario.
Jared Smith
2
Esta no era realmente la pregunta. Pero fue útil para hacer una disidencia. Decidí hacerlo. Estoy dispuesto a aprender más sobre el funcionamiento interno de todo en lo que se basa. Y me gusta la programación. De esta manera espero comprender mejor el funcionamiento interno de las computadoras. Es solo por diversión.
Tristan
10
No estoy de acuerdo con la última oración. Aprenda cómo hacerlo correctamente antes de desarrollar malos hábitos.
glglgl
2
@glglgl IDK, si leo (o escribo) un fragmento de JavaScript en la web, lo hago con el entendimiento de que no está listo para la producción: no tendrá un manejo de excepciones, podría ser O (n ^ 2), etc. Ninguno de eso es necesario para transmitir el punto. Todo esto es necesario para el código de producción. ¿Por qué es esto diferente? Puedo escribir ingenuamente C para mi propia edificación y entender intelectualmente que si quisiera publicarlo, tendría que hacer mucho más trabajo.
Jared Smith
14

Esta es una ENORME pregunta con toneladas de respuestas, pero la versión corta es que cada lenguaje de programación está especializado para diferentes situaciones. Por ejemplo, JavaScript para web, C para cosas de bajo nivel, C # para cualquier cosa de Windows, etc. Es útil saber lo que quiere hacer una vez que conoce la programación para decidir qué lenguaje de programación elegir.

Para abordar su último punto, por qué C / C ++ sobre Java / Python, a menudo se reduce a la velocidad. Hago juegos, y Java / C # recientemente está alcanzando velocidades que son lo suficientemente buenas para que los juegos se ejecuten. Después de todo, si quieres que tu juego se ejecute a 60 cuadros por segundo, y quieres que tu juego haga mucho (el renderizado es particularmente costoso), entonces necesitas que el código se ejecute lo más rápido posible. Python / Java / C # / Muchos otros se ejecutan en "intérpretes", una capa adicional de software que maneja todas las tareas tediosas que C / C ++ no hace, como administrar la memoria y la recolección de basura. Esa sobrecarga adicional ralentiza las cosas, por lo que casi todos los juegos grandes que ves se hicieron (en los últimos 10 años, de todos modos) en C o C ++. Hay excepciones: el motor del juego Unity usa C # * y Minecraft usa Java, pero son la excepción, no la regla. En general,

* Incluso Unity no es todo C #, grandes partes de él son C ++ y solo usas C # para tu código de juego.

EDITAR Para responder a algunos de los comentarios que aparecieron después de publicar esto: Tal vez estaba simplificando demasiado, solo estaba dando una imagen general. Con la programación, la respuesta nunca es simple. Hay intérpretes para C, Javascript puede ejecutarse fuera del navegador y C # puede ejecutarse en casi cualquier cosa gracias a Mono. Diferentes lenguajes de programación están especializados para diferentes dominios, pero algún programador en algún lugar probablemente descubrió cómo ejecutar cualquier lenguaje en cualquier contexto. Como el OP parecía no saber mucha programación (suposición de mi parte, perdón si me equivoco), estaba tratando de mantener mi respuesta simple.

En cuanto a los comentarios acerca de que C # es casi tan rápido como C ++, la palabra clave es casi. Cuando estaba en la universidad, visitamos muchas compañías de juegos, y mi maestro (que nos había estado alentando a alejarnos de C # y pasar a C ++ todo el año) preguntó a los programadores en cada compañía a las que acudíamos sobre por qué C ++ sobre C #, y cada una de ellas. dijo C # es demasiado lento. En general, se ejecuta rápidamente, pero el recolector de basura puede afectar el rendimiento porque no puede controlar cuándo se ejecuta, y tiene el derecho de ignorarlo si no desea ejecutarlo cuando lo recomienda. Si necesita que algo sea de alto rendimiento, no quiere algo tan impredecible como eso.

Para responder a mi comentario de "solo alcanzar velocidades", sí, gran parte de los aumentos de velocidad de C # provienen de un mejor hardware, pero a medida que el .NET framework y el compilador de C # han mejorado, ha habido algunas aceleraciones allí.

Sobre el comentario de "los juegos están escritos en el mismo idioma que el motor", depende. Algunos lo son, pero muchos están escritos en un híbrido de idiomas. Unreal puede hacer UnrealScript y C ++, Unity hace C # Javascript y Boo, muchos otros motores escritos en C o C ++ usan Python o Lua como lenguajes de script. No hay una respuesta simple allí.

Y solo porque me molestó leer "a quién le importa si tu juego se ejecuta a 200 fps o 120 fps", si tu juego se ejecuta a más de 60 fps, probablemente estés perdiendo el tiempo de la CPU, ya que el monitor promedio ni siquiera actualiza eso rápido. Algunos de gama alta y más nuevos lo hacen, pero no es estándar (todavía ...).

Y sobre el comentario de "ignorar décadas de tecnología", todavía estoy en mis primeros 20 años, así que cuando extrapolo hacia atrás, me hago eco de lo que me han dicho los programadores más viejos y más experimentados. Obviamente, eso se disputará en un sitio como este, pero vale la pena considerarlo.

Cody
fuente
44
" C # para cualquier cosa Windows " - Oh, eso es una falacia. E incluso das un ejemplo. Unidad. AFAIK No está escrito, proporciona API de C # porque el lenguaje es agradable y adaptable. Está realmente bien diseñado. Y me gusta más C ++, pero el crédito se debe dar donde corresponde. ¿Quizás mezcló C # con .NET? Pasan el rato juntos con bastante frecuencia.
luk32
2
"Incluso Unity no es todo C #, grandes partes de él son C ++" ¿Y? Los juegos en Unity a menudo usan C # ampliamente, y han existido desde hace bastante tiempo. Sugerir que C # está "alcanzando velocidades recientemente" o necesita más contexto o corre el riesgo de ser ciego a la tecnología de esta década.
NPSF3000
2
Casi todos los juegos grandes se escribieron en el lenguaje del motor que usaban: la cantidad de trabajo que habría necesitado duplicarse era tan grande que ni siquiera valía la pena tener en cuenta ninguna otra consideración técnica. El renderizado es realmente costoso, pero hoy en día todo está escrito en sombreadores y el lenguaje del bucle lógico es irrelevante.
Peter Taylor
2
C # siempre se ha compilado JIT (a diferencia de Java, donde su comentario es correcto), y era bastante capaz de velocidades de ejecución muy similares a C ++ desde el principio si sabía lo que estaba haciendo. Eso es 2003, algo que no consideraría reciente. La velocidad sin procesar no es el problema principal para los juegos (especialmente con sombreadores programables en la GPU), hay otras cosas que hicieron que lenguajes como C # sean más o menos populares a veces. Dos problemas principales son las API (que están muy orientadas a C, y la interfaz puede ser costosa) y GC (principalmente para problemas de latencia, no rendimiento bruto).
Luaan
1
@gbjbaanb No se trata solo de que las CPU sean más rápidas: un gran problema es que C ++ y C tuvieron décadas para perfeccionar sus compiladores y tiempo de ejecución, mientras que Java comenzó básicamente desde cero (diseñado principalmente como una plataforma multiplataforma). A medida que la VM mejoró (por ejemplo, el cambio de intérprete a un compilador JIT, mejoró GC ...), también mejoró el rendimiento de las aplicaciones Java. Gran parte de la ventaja que aún tiene C / C ++ está en el enfoque "esperemos que nada se rompa", evitando muchas comprobaciones que se consideran "innecesarias". Pero sigue siendo un enorme problema de memoria; de hecho, las mejoras en el uso de la CPU a menudo significaron un peor rendimiento de la memoria :)
Luaan
13

Es curioso que afirmes que C es inseguro porque "tiene punteros". Lo contrario es cierto: Java y C # tienen prácticamente solo punteros (para tipos no nativos). El error más común en Java es probablemente la excepción de puntero nulo (cf. https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare ). El segundo error más común es probablemente tener referencias ocultas a objetos no utilizados (por ejemplo, los Diálogos cerrados no se eliminan) que, por lo tanto, no se pueden liberar, lo que lleva a programas de larga duración con una huella de memoria cada vez mayor.

Hay dos mecanismos básicos que hacen que C # y Java sean más seguros y más seguros de dos maneras diferentes:

  • La recolección de basura hace que sea menos probable que el programa intente acceder a objetos descartados. Esto hace que el programa sea menos probable que finalice inesperadamente. A diferencia de C, Java y C # por defecto asignan datos no nativos dinámicamente. Esto hace que la lógica del programa sea realmente más compleja, pero la recolección de basura incorporada, a un costo, se hace cargo de la parte difícil.

Los recientes punteros inteligentes de C ++ hacen que ese trabajo sea más fácil para los programadores.

  • Java y C # compilan en un código intermedio que es interpretado / ejecutado por un tiempo de ejecución elaborado. Esto agrega un nivel de seguridad porque el tiempo de ejecución puede detectar actividades ilícitas de un programa. Incluso si el programa está codificado de forma insegura (lo cual es posible en ambos idiomas), el tiempo de ejecución respectivo en teoría evita "irrumpir" en el sistema.
    El tiempo de ejecución no protege, por ejemplo, contra intentos de desbordamiento del búfer, pero en teoría no permite explotaciones de dichos programas. Con C y C ++, por el contrario, el programador tiene que codificar de forma segura para evitar exploits. Esto generalmente no se logra de inmediato, pero necesita revisiones e iteraciones.

Sin embargo, vale la pena señalar que el tiempo de ejecución elaborado también es un riesgo de seguridad. Me parece que Oracle está actualizando la JVM cada dos semanas debido a problemas de seguridad recientemente descubiertos. Por supuesto, es mucho más difícil verificar la JVM que un solo programa.

La seguridad de un tiempo de ejecución elaborado es, por lo tanto, ambigua y hasta cierto punto engañosa: su programa de C promedio puede, con revisiones e iteraciones, hacerse razonablemente seguro. Su programa Java promedio es tan seguro como la JVM; es decir, en realidad no. Nunca.

El artículo sobre el gets()que se vincula refleja las decisiones históricas de la biblioteca que se tomarían de manera diferente hoy, no el lenguaje central.

Peter A. Schneider
fuente
3
Creo que el punto del autor original es que en C puedes tomar medidas sin control sobre esos punteros. En Java, obtienes una buena excepción de inmediato: en C, es posible que no te des cuenta de que estás leyendo una ubicación no válida hasta que el estado de tu aplicación esté dañado.
Sam Dufel
1
Además, stackoverflow.com/questions/57483/… : sería más exacto decir que Java tiene "prácticamente solo referencias".
Sam Dufel
44
He visto todo tipo de errores interesantes como resultado de los intentos de evitar punteros explícitos. Por lo general, el problema fundamental es la confusión entre copia y referencia. En C, si le paso un puntero a algo, sabe que modificarlo afectará al original. Algunos de los intentos de evitar punteros ofuscan esta distinción, lo que lleva a un laberinto de copias profundas, copias superficiales y confusión general.
Arlie Stephens
Afirmar que JVM de Oracle apesta (desde el punto de vista de hemorragias de vulnerabilidades de seguridad explotables) y, por lo tanto, los tiempos de ejecución de los lenguajes administrados en general introducen más preocupaciones de seguridad que evitar el uso de un lenguaje administrado, es como decir que Adobe Flash es horrible como fuente de inseguridad y programa que ¿La reproducción de video y animación desde un sitio web debe ser intrínsecamente insegura? No todos los tiempos de ejecución de Java son tan malos como la abominación JVM de Oracle / Sun de la década de 1990, y no todos los lenguajes administrados son Java. (Bueno, obviamente.)
mayormente informado el
@halfinformed Bueno; Estaba diciendo que un programa es tan seguro como su tiempo de ejecución, y que el programa "su promedio" (léase: pequeño-ish) puede, con un esfuerzo, hacerse más seguro que cualquier tiempo de ejecución grande como un intérprete de código de bytes. Esa afirmación parece innegable. Si un programa independiente en particular o un tiempo de ejecución en particular es más o menos seguro que el otro depende de su respectiva complejidad y diseño, codificación y calidad de mantenimiento. Por ejemplo, no diría que sendmail es más seguro que Java VM de Oracle; pero qmail puede ser.
Peter A. Schneider
10

Como la "seguridad" cuesta velocidad, los idiomas "más seguros" funcionan a una velocidad más lenta.

Pregunta por qué usar un lenguaje "peligroso" como C o C ++, que alguien le escriba un controlador de video o similar en Python o Java, etc. y vea cómo se siente acerca de la "seguridad" :)

En serio, debes estar lo más cerca posible de la memoria central de la máquina para poder manipular píxeles, registros, etc. Java o Python no pueden hacer esto con ningún tipo de velocidad digna de rendimiento ... C y C ++ ambos le permite hacer esto a través de punteros y similares ...

Wintermut3
fuente
20
No es cierto en general que la seguridad cuesta velocidad . Los idiomas más seguros disponibles hacen la mayoría de las comprobaciones en tiempo de compilación. O'Caml, Ada, Haskell, Rust no están muy por detrás de C en términos de velocidad de ejecución promedio. En lo que suelen incurrir es en una sobrecarga significativa en el tamaño del programa, la eficiencia de la memoria, la latencia y, obviamente, el tiempo de compilación. Y sí, tienen dificultades con las cosas cercanas al metal. Pero eso no es realmente un problema de velocidad.
Leftaroundabout
66
Además, C no hace lo que crees que hace. C es una máquina abstracta . No le da acceso directo a nada, eso es algo bueno. Ni siquiera puede mirar el ensamblaje moderno para ver cuánto C se esconde de usted: el ensamblaje moderno (por ejemplo, TASM) se habría considerado un lenguaje de alto nivel cuando se desarrolló C. Estaría muy contento si alguien escribiera controladores en un lenguaje "seguro", gracias, eso ayudaría bastante a evitar muchos de esos BSOD y bloqueos, sin mencionar los agujeros de seguridad :) Y lo más importante, hay lenguajes de sistemas que son mucho más seguros que C.
Luaan
3
@Wintermute Realmente desea buscar Rust antes de hacer comentarios sobre cómo las características de seguridad necesariamente cuestan velocidad. Demonios, el sistema de tipos de bajo nivel de C en realidad inhibe muchas optimizaciones muy útiles que los compiladores podrían hacer de otra manera (particularmente cuando se considera que prácticamente ningún gran proyecto c logra evitar no violar el alias estricto en alguna parte ).
Voo
77
@Wintermute Sí, el mito de que no se puede hacer que C / C ++ sea más seguro sin introducir una sobrecarga de rendimiento es muy persistente, por eso lo tomo en serio (hay algunas áreas en las que esto es cierto [comprobación de límites]). Ahora, ¿por qué el óxido no está más extendido? Historia y complejidad. Rust todavía es relativamente nuevo y muchos de los sistemas más grandes escritos en C existieron antes de que Rust se inventara nunca; no reescribirá un millón de LOC en un nuevo idioma, incluso si fuera mucho más seguro. Además, cada programador y su perro saben C, Rust? Buena suerte encontrando suficientes personas.
Voo
3
@Voo Dogs haciendo C? ... no es de extrañar que haya visto tantos códigos malos por ahí ... j / k Punto tomado sobre Rust (acabo de descargarlo e instalarlo, por lo que puede tener otro convertidor para agregar) BTW en lo que respecta a Rust hacerlo bien ... Podría hacer el mismo aumento para "D" :)
Wintermut3
9

Además de todo lo anterior, también hay un caso de uso bastante común, que utiliza C como una biblioteca común para otros lenguajes.

Básicamente, casi todos los idiomas tienen una interfaz API para C.

Ejemplo simple, intente crear una aplicación común para Linux / IOS / Android / Windows. Además de todas las herramientas que existen, lo que terminamos fue hacer una biblioteca central en C y luego cambiar la GUI para cada entorno, es decir:

  • IOS: ObjectiveC puede usar bibliotecas C de forma nativa
  • Android: Java + JNI
  • Linux / Windows / MacOS: con GTK / .Net puede usar bibliotecas nativas. Si usa Python, Perl, Ruby, cada uno de ellos tiene interfaces API nativas. (Java nuevamente con JNI).

Mis dos centavos,

Nito
fuente
Una de las razones por las que me encanta usar, digamos, PHP, es porque casi todas sus bibliotecas están escritas en C, afortunadamente, o PHP sería insoportablemente lento :) PHP es excelente para escribir código descuidado sin temor a haciendo algo 'peligroso' (y es por eso que tiendo a escribir mucho más código PHP que cualquier otra cosa; ¡me gusta el código descuidado!: D), pero es bueno saber que debajo de muchas de esas llamadas a funciones hay buenos y confiables Las bibliotecas de C para darle un impulso de rendimiento ;-) Por el contrario, escribir código descuidado en C es un gran no-no ...
Gwyneth Llewelyn
7

Una dificultad fundamental con C es que el nombre se usa para describir varios dialectos con una sintaxis idéntica pero una semántica muy diferente. Algunos dialectos son mucho más seguros que otros.

En C, como fue diseñado originalmente por Dennis Ritchie, las declaraciones de C generalmente se asignarían a las instrucciones de la máquina de manera predecible. Debido a que C podía ejecutarse en procesadores que se comportaban de manera diferente cuando ocurrían cosas como el desbordamiento aritmético firmado, un programador que no sabía cómo se comportaría una máquina en caso de desbordamiento aritmético tampoco sabría qué código C se ejecuta en esa máquina, pero Si se sabe que una máquina se comporta de cierta manera (p. ej., envoltura silenciosa del complemento a dos), las implementaciones en esa máquina normalmente harían lo mismo. Una de las razones por las que C se ganó la reputación de ser rápido fue que, en los casos en que los programadores sabían que el comportamiento natural de una plataforma en escenarios extremos se ajustaba a sus necesidades, no era necesario que el programador o el compilador escribieran código para generar tales escenarios. .

Desafortunadamente, los escritores de compiladores han opinado que, dado que el Estándar no impone requisitos sobre lo que las implementaciones deben hacer en tales casos (laxitud que estaba destinada a permitir implementaciones de hardware que podrían no comportarse de manera predecible), los compiladores deben sentirse libres de generar código que niegue las leyes de tiempo y causalidad.

Considera algo como:

int hey(int x)
{
   printf("%d", x);
   return x*10000;
}
void wow(int x)
{
  if (x < 1000000)
    printf("QUACK!");
  hey(x);    
}

La teoría del compilador hipermoderno (pero de moda) sugeriría que el compilador debería mostrar "¡QUACK!" incondicionalmente, dado que en cualquier caso donde la condición era falsa, el programa terminaría invocando un comportamiento indefinido que realizaba una multiplicación cuyo resultado sería ignorado de todos modos. Dado que el estándar permitiría a un compilador hacer lo que quiera en ese caso, le permite al compilador generar "QUACK!".

Si bien C solía ser más seguro que el lenguaje ensamblador, cuando se usan compiladores hipermodernos, lo contrario es cierto. En lenguaje ensamblador, el desbordamiento de enteros puede hacer que un cálculo produzca resultados sin sentido, pero en la mayoría de las plataformas será el alcance de sus efectos. Si los resultados terminan siendo ignorados de todos modos, el desbordamiento no importará. Sin embargo, en C hipermoderna, incluso lo que normalmente serían formas "benignas" de Comportamiento indefinido (como un desbordamiento de enteros en un cálculo que termina siendo ignorado) puede causar la ejecución arbitraria del programa.

Super gato
fuente
1
incluso en un compilador hipermoderno, C no verifica los límites de las matrices. si lo hiciera, eso no sería compatible con la definición del lenguaje. Utilizo ese hecho a veces para hacer matrices con un puntero adicional en el medio de la matriz para tener índices negativos.
robert bristow-johnson
1
Me gustaría ver evidencia de tu ejemplo produciendo "QUACK!" incondicionalmente x ciertamente puede ser mayor que 1000000 en el punto de comparación, y una evaluación posterior que resultaría en un desbordamiento no lo impide. Más aún, si tiene habilitada la alineación que permite eliminar la multiplicación desbordante, su argumento sobre las restricciones de rango implícito no se cumple.
Graham
2
@ robertbristow-johnson: En realidad, el Estándar dice explícitamente que dado int arr[5][[5], por ejemplo , un intento de acceso arr[0][5]generará un Comportamiento indefinido. Dicha regla hace posible que un compilador al que se le dé algo como arr[1][0]=3; arr[0][i]=6; arr[1][0]++;inferir arr[1][0]sea ​​igual a 4, sin tener en cuenta el valor de i.
supercat
2
@ robertbristow-johnson: incluso si el compilador asigna matrices dentro de una estructura secuencialmente sin espacios, eso no garantiza que la indexación de una de las matrices garantice que afecte a otra. Vea godbolt.org/g/Avt3KW para ver un ejemplo de cómo gcc tratará dicho código.
supercat
1
@ robertbristow-johnson: Comenté la asamblea para explicar lo que está haciendo. El compilador ve que el código almacena 1 en s-> arr2 [0] y luego incrementa s-> arr2 [0], por lo que gcc combina esas dos operaciones haciendo que el código simplemente almacene el valor del valor 2, sin considerar la posibilidad de que la escritura interviniente a s-> arr1 [i] podría afectar el valor de s-> arr1 [0] (ya que, de acuerdo con el Estándar, no puede).
supercat
5

Razones históricas. No suelo escribir código nuevo, principalmente mantengo y extiendo las cosas viejas que han estado funcionando durante décadas. Estoy feliz de que sea C y no Fortran.

Puedo irritarme cuando un estudiante dice: "¿pero por qué haces esta horrible X cuando podrías estar haciendo Y?". Bueno, X es el trabajo que tengo y paga las facturas muy bien. He hecho Y en ocasiones, y fue divertido, pero X es lo que la mayoría de nosotros hacemos.

RedSonja
fuente
5

¿Qué es "peligroso"?

La afirmación de que C es "peligroso" es un tema de conversación frecuente en las guerras de la llama del lenguaje (con mayor frecuencia en comparación con Java). Sin embargo, la evidencia de esta afirmación no está clara.

C es un lenguaje con un conjunto particular de características. Algunas de estas características pueden permitir ciertos tipos de errores que no están permitidos por otros tipos de lenguajes (el riesgo de la administración de memoria de C generalmente se resalta). Sin embargo, esto no es lo mismo que un argumento de que C es más peligroso que otros lenguajes en general . No conozco a nadie que proporcione evidencia convincente sobre este punto.

Además, "peligroso" depende del contexto: ¿qué está tratando de hacer y qué tipo de riesgos le preocupan?

En muchos contextos, consideraría que C es más "peligroso" que un lenguaje de alto nivel, ya que requiere una implementación más manual de la funcionalidad básica, lo que aumenta el riesgo de errores. Por ejemplo, hacer un procesamiento de texto básico o desarrollar un sitio web en C generalmente sería tonto, porque otros lenguajes tienen características que lo hacen mucho más fácil.

Sin embargo, C y C ++ se usan ampliamente para sistemas de misión crítica, porque un lenguaje más pequeño con un control más directo de hardward se considera "más seguro" en ese contexto. De una muy buena respuesta de desbordamiento de pila :

Aunque C y C ++ no se diseñaron específicamente para este tipo de aplicación, se usan ampliamente para software incrustado y crítico para la seguridad por varias razones. Las principales propiedades de la nota son el control sobre la administración de la memoria (que le permite evitar tener que recolectar basura, por ejemplo), bibliotecas de tiempo de ejecución básicas simples y bien depuradas y soporte para herramientas maduras. Muchas de las cadenas de herramientas de desarrollo integradas en uso hoy en día se desarrollaron por primera vez en las décadas de 1980 y 1990, cuando se trataba de tecnología actual y provienen de la cultura Unix que prevalecía en ese momento, por lo que estas herramientas siguen siendo populares para este tipo de trabajo.

Si bien el código de administración de memoria manual debe verificarse cuidadosamente para evitar errores, permite un grado de control sobre los tiempos de respuesta de la aplicación que no está disponible con idiomas que dependen de la recolección de basura. Las bibliotecas de tiempo de ejecución central de los lenguajes C y C ++ son relativamente simples, maduras y bien entendidas, por lo que se encuentran entre las plataformas más estables disponibles.

Comunidad
fuente
2
Diría que la C hipermoderna también es más peligrosa que el lenguaje ensamblador o los dialectos genuinos de bajo nivel de C que se comportan constantemente como si tradujeran constantemente las operaciones de C en operaciones de código de máquina sin tener en cuenta los casos extremos donde las operaciones de código de máquina natural tienen un comportamiento definido pero el Estándar C no impondría ningún requisito. El enfoque hipermoderno donde un desbordamiento de enteros puede negar las reglas del tiempo y la causalidad parece mucho menos susceptible de generar código seguro.
supercat
5

Para agregar a las respuestas existentes, está muy bien decir que va a elegir Python o PHP para su proyecto, debido a su relativa seguridad. Pero alguien tiene que implementar esos lenguajes y, cuando lo hagan, probablemente lo harán en C. (O, bueno, algo así).

Por eso es que la gente usa C - para crear las herramientas menos peligrosos que se desea utilizar.

Carreras de ligereza en órbita
fuente
2

Permíteme reformular tu pregunta:

Estoy considerando aprender [herramienta].

Pero, ¿por qué la gente usa [herramienta] (o [herramienta relacionada]) si [ellos] pueden usarse 'peligrosamente'?

Cualquier herramienta interesante se puede usar peligrosamente, incluidos los lenguajes de programación. Usted aprenderá más para que pueda hacer más (y por lo menos peligro de que se crea cuando se utiliza la herramienta). En particular, aprende la herramienta para que pueda hacer lo que esa herramienta es buena (y tal vez reconocer cuándo esa herramienta es la mejor herramienta de las herramientas que conoce).

Por ejemplo, si necesita colocar un agujero cilíndrico de 6 mm de diámetro y 5 cm de profundidad en un bloque de madera, un taladro es una herramienta mucho mejor que un analizador LALR. Si sabe cuáles son estas dos herramientas, sabe cuál es la herramienta correcta. Si ya sabes cómo usar un taladro, ¡voila !, hoyo.

C es solo otra herramienta. Es mejor para algunas tareas que para otras. Las otras respuestas aquí abordan esto. Si aprende algo de C, reconocerá cuándo es la herramienta correcta y cuándo no.

Eric Towers
fuente
Esta gran cantidad de respuestas es por qué las preguntas se descartan como "principalmente basadas en la opinión". ¡No digas que C tiene sus ventajas, di cuáles son!
reinierpost
1

Estoy considerando aprender C

No hay una razón específica para no aprender C, pero sugeriría C ++. Ofrece mucho de lo que hace C (ya que C ++ es un súper conjunto de C), con una gran cantidad de "extras". Aprender C antes que C ++ es innecesario: son efectivamente lenguajes separados.

Dicho de otra manera, si C fuera un conjunto de herramientas para trabajar la madera, probablemente sería:

  • martillo
  • uñas
  • Sierra de mano
  • taladro de mano
  • lijadora de bloque
  • cincel (tal vez)

Puede construir cualquier cosa con estas herramientas, pero cualquier cosa agradable requiere potencialmente mucho tiempo y habilidad.

C ++ es la colección de herramientas eléctricas en su ferretería local.

Si se apega a las características básicas del lenguaje para comenzar, C ++ tiene relativamente poca curva de aprendizaje adicional.

Pero, ¿por qué las personas usan C (o C ++) si se puede usar 'peligrosamente'?

Porque algunas personas no quieren muebles de IKEA. =)

En serio, aunque muchos lenguajes que son "superiores" a C o C ++ pueden tener cosas que los hacen (potencialmente) "más fáciles" de usar en ciertos aspectos, esto no siempre es algo bueno. Si no le gusta la forma en que se hace algo o no se proporciona una función, es probable que no haya mucho que pueda hacer al respecto. Por otro lado, C y C ++ proporcionan suficientes características de lenguaje de "bajo nivel" (incluidos punteros) para que pueda acceder a muchas cosas de manera bastante directa (especialmente hardware o sistema operativo) o construirlo usted mismo, lo que puede no ser posible en otros idiomas implementados.

Más específicamente, C tiene el siguiente conjunto de características que lo hacen deseable para muchos programadores:

  • Velocidad : debido a su relativa simplicidad y optimizaciones del compilador a lo largo de los años, es nativamente muy rápido. Además, muchas personas han descubierto muchos atajos a objetivos específicos al usar el lenguaje, lo que lo hace aún más rápido.
  • Tamaño : por razones similares a las enumeradas para la velocidad, los programas en C pueden hacerse muy pequeños (tanto en términos de tamaño ejecutable como de uso de memoria), lo cual es deseable para entornos con memoria limitada (es decir, integrada o móvil).
  • Compatibilidad : C ha existido durante mucho tiempo y todos tienen herramientas y bibliotecas para ello. El lenguaje en sí tampoco es exigente: espera que un procesador ejecute instrucciones y memoria para guardar cosas y eso es todo.

    Además, hay algo conocido como una interfaz binaria de aplicación (ABI) . En resumen, es una forma para que los programas se comuniquen a nivel de código de máquina, lo que puede tener ventajas sobre una interfaz de programación de aplicaciones (API) . Si bien otros lenguajes como C ++ pueden tener una ABI, generalmente son menos uniformes (acordados) que los C, por lo que C es un buen lenguaje básico cuando desea utilizar una ABI para comunicarse con otro programa por alguna razón.

¿Por qué los programadores no solo usan Java o Python u otro lenguaje compilado como Visual Basic?

Eficiencia (y ocasionalmente esquemas de administración de memoria que no pueden implementarse sin un acceso relativamente directo a la memoria).

El acceso directo a la memoria con punteros presenta muchos trucos ingeniosos (generalmente rápidos) cuando puede poner sus patas sucias en los pequeños y ceros en sus cubículos de memoria directamente y no tener que esperar a que ese viejo maestro entregue los juguetes solo a la hora de jugar y luego recogerlos de nuevo.

En resumen, agregar cosas potencialmente crea un retraso o, de lo contrario, introduce una complejidad no deseada.

Con respecto a los lenguajes con secuencias de comandos y cosas por el estilo, debe trabajar duro para obtener los lenguajes que requieren que los programas secundarios se ejecuten de manera tan eficiente como C (o cualquier lenguaje compilado) de forma nativa. Agregar un intérprete sobre la marcha introduce inherentemente la posibilidad de disminuir la velocidad de ejecución y aumentar el uso de memoria porque está agregando otro programa a la mezcla. La eficiencia de sus programas depende tanto de la eficiencia de este programa secundario como de qué tan bien (mal =) escribió su código de programa original. Sin mencionar que su programa a menudo depende completamente del segundo programa para ejecutarse. ¿Ese segundo programa no existe por alguna razón en un sistema en particular? Código no ir.

De hecho, la introducción de algo "extra" potencialmente ralentiza o complica su código. En los lenguajes "sin punteros de miedo", siempre está esperando que otros fragmentos de código se limpien detrás de usted o que de otra manera descubra formas "seguras" de hacer las cosas, porque su programa todavía está haciendo las mismas operaciones de acceso a la memoria que se podrían hacer con punteros Simplemente no eres el que lo maneja (por lo que no puedes joderlo, genio = P).

Por peligroso, quiero decir con punteros y otras cosas similares. [...] Como la pregunta de desbordamiento de pila ¿ Por qué la función gets es tan peligrosa que no debería usarse?

Por la respuesta aceptada:

"Seguía siendo una parte oficial del lenguaje hasta el estándar ISO C de 1999, pero fue eliminado oficialmente por el estándar de 2011. La mayoría de las implementaciones de C todavía lo admiten, pero al menos gcc emite una advertencia para cualquier código que lo use".

La idea de que, debido a que algo se puede hacer en un idioma, debe hacerse es una tontería. Los idiomas tienen fallas que se arreglan. Por razones de compatibilidad con el código anterior, esta construcción aún se puede utilizar. Pero no hay nada (probable) que obligue a un programador a usar gets () y, de hecho, este comando fue esencialmente reemplazado por alternativas más seguras.

Más aún, el problema con gets () no es un problema de puntero per se. Es un problema con un comando que no necesariamente sabe cómo usar la memoria de manera segura. En un sentido abstracto, se trata de cuestiones de puntero: leer y escribir cosas que no debes. Eso no es un problema con los punteros; Es un problema con la implementación del puntero.

Para aclarar, los punteros no son peligrosos hasta que accidentalmente acceda a una ubicación de memoria que no tenía intención de hacer. Y aun así, eso no garantiza que su computadora se derrita o explote. En la mayoría de los casos, su programa dejará de funcionar (correctamente).

Dicho esto, debido a que los punteros brindan acceso a ubicaciones de memoria y a que los datos y el código ejecutable existen en la memoria juntos, existe un peligro real de corrupción accidental como para que desee administrar la memoria correctamente.

Hasta ese punto, debido a que las operaciones de acceso directo a la memoria a menudo brindan menos beneficios en general de lo que podrían haber sido hace años, incluso los lenguajes no recolectados como C ++ han introducido cosas como punteros inteligentes para ayudar a cerrar la brecha entre la eficiencia y la seguridad de la memoria.

En resumen, hay muy pocas razones para temer al puntero siempre que se use de manera segura. Solo tome una pista de la versión de South Park de Steve "El cazador de cocodrilos" Irwin: no ande metiendo el pulgar en los huecos de los cocodrilos .

Anaksunaman
fuente
2
No estoy de acuerdo con la sugerencia de aprender C ++ en lugar de C. Escribir bien C ++ es más difícil que escribir bien C y leer C ++ es mucho más difícil que leer C. Por lo tanto, la curva de aprendizaje de C ++ es mucho más pronunciada. "C ++ es un superconjunto de C" Esto es más o menos como decir que las botas son un superconjunto de zapatillas. Tienen diferentes ventajas y usos, y cada uno tiene características que el otro no.
martinkunev
"Escribir un buen C ++ es más difícil que escribir un buen C" - Absolutamente. =) "[R] leer C ++ es mucho más difícil que leer C" - Cualquier programación avanzada es indistinguible de la magia ;-) Mis dos centavos son que esto depende mucho más del programador que del lenguaje, aunque C ++ no hace mucho para ayudarse a sí mismo. en esta categoria. "Entonces, la curva de aprendizaje de C ++ es mucho más pronunciada". - A la larga, sí. A corto plazo, menos (mi opinión). Como anécdota, es probable que la mayoría de los cursos de idiomas básicos en C y C ++ cubran aproximadamente los mismos tipos generales de material, excepto las clases para C ++.
Anaksunaman
2
"Tienen diferentes ventajas y usos, y cada uno tiene características que el otro no tiene". - Como se mencionó "No hay una razón específica para no aprender C [.]" C es un buen lenguaje y me apego a eso. Si se adapta a OP u otra persona, apoyo totalmente aprenderlo. =)
Anaksunaman
Learning C te enseña cómo funciona la máquina (no completamente, pero aún un paso más cerca del metal). Esa es una muy buena razón para aprenderlo.
Agent_L
1

Como siempre, el lenguaje de programación es solo una consecuencia de la resolución de problemas. De hecho, debe aprender no solo C sino muchos lenguajes diferentes (y otras formas de programar una computadora, ya sean herramientas GUI o intérpretes de comandos) para tener una caja de herramientas decente para usar al resolver problemas.

A veces encontrará que un problema se presta bien a algo que está incluido en las bibliotecas predeterminadas de Java, en tal caso, puede elegir Java para aprovechar eso. En otros casos, puede ser que necesite hacer algo en Windows que sea mucho más simple en el tiempo de ejecución de .NET, por lo que puede usar C # o VB. Podría haber una herramienta gráfica o un script de comando que resuelva su problema, luego puede usarlos. Tal vez necesite escribir una aplicación GUI en múltiples plataformas, Java podría ser una opción, dadas las bibliotecas incluidas en el JDK, pero una vez más, una plataforma de destino puede carecer de un JRE, por lo que tal vez elija C y SDL (o similar).

C tiene una posición importante en este conjunto de herramientas, ya que es general, pequeño y rápido y también se compila en código de máquina. También es compatible en todas las plataformas bajo el sol (sin embargo, no sin recompilar).

La conclusión es que debe aprender tantas herramientas, lenguajes y paradigmas como sea posible.

Aléjese de la mentalidad: "Soy un programador X" (X = C, C ++, Java, etc.)

Solo usa "Soy programador".

Un programador resuelve problemas y diseña algoritmos instruyendo a las máquinas para que realicen la carga de trabajo. Fin de la historia. Esto es irrelevante para el lenguaje. Su habilidad más importante es la resolución de problemas y el desglose lógico de problemas estructurados, la habilidad / elección del lenguaje es SIEMPRE secundaria y / o una consecuencia de la naturaleza del problema.

Un camino interesante si está interesado en C es ampliar su conjunto de habilidades con Go. Go es realmente una C mejorada, con recolección de basura e interfaces, así como un buen modelo / canales integrados de subprocesos, que también brindan muchos de los beneficios de C (como la aritmética de punteros y la compilación de código de máquina).

Richard Tyregrim
fuente
0

Depende de lo que pretendas hacer con él. C fue diseñado como un reemplazo para el lenguaje ensamblador y es el lenguaje de alto nivel más cercano al lenguaje máquina. Por lo tanto, tiene unos gastos generales bajos en tamaño y rendimiento, y es adecuado para la programación de sistemas y otras tareas que requieren una pequeña huella y se acercan al hardware subyacente.

Jonathan Rosenne
fuente
0

Cuando trabaja a nivel de bits y bytes, de memoria como una recopilación de datos homogénea sin procesar, como a menudo se requeriría para implementar de manera efectiva los asignadores y las estructuras de datos más eficientes, no hay seguridad. La seguridad es predominantemente un concepto fuerte relacionado con el tipo de datos, y un asignador de memoria no funciona con los tipos de datos. Funciona con bits y bytes para agruparse con esos mismos bits y bytes que representan potencialmente un tipo de datos en un momento y otro más adelante.

No importa si usa C ++ en ese caso. Todavía estaría rociando static_caststodo el código para emitir desde void*punteros y aún trabajando con bits y bytes y solo lidiando con más problemas relacionados con el respeto del sistema de tipos en este contexto que C, que tiene un sistema de tipos mucho más simple donde eres libre a memcpybits y bytes sin preocuparse por demoler el sistema de tipos.

De hecho, a menudo es más difícil trabajar en C ++, un lenguaje más seguro en general, en contextos de bits y bytes de tan bajo nivel sin escribir un código aún más peligroso que en C, ya que podría estar arrasando sobre el sistema de tipos de C ++ y haciendo cosas como sobrescribir vptrs y no invocar constructores de copia y destructores en los momentos apropiados. Si se toma el tiempo adecuado para respetar estos tipos y utiliza la ubicación nueva e invoca manualmente a los dtors, etc., se expondrá al mundo del manejo de excepciones en un contexto de nivel demasiado bajo para que RAII sea práctico y logre excepciones. La seguridad en un contexto de tan bajo nivel es muy difícil (tiene que fingir que casi cualquier función puede lanzar y capturar todas las posibilidades y revertir cualquier efecto secundario como una transacción indivisible como si nada sucediera). El código C a menudo puede "

Y sería imposible implementar tales asignadores en idiomas que no le permitan ser "peligrosos" aquí; tendría que apoyarse en los asignadores que proporcionan (implementados muy probablemente en C o C ++) y esperar que sea lo suficientemente bueno para sus propósitos. Y casi siempre hay asignadores y estructuras de datos más eficientes pero menos generales adecuados para sus propósitos específicos pero mucho más estrictamente aplicables ya que están diseñados específicamente para sus propósitos.

La mayoría de las personas no necesitan los gustos de C o C ++, ya que solo pueden llamar al código implementado originalmente en C o C ++ o posiblemente incluso en un ensamblaje ya implementado para ellos. Muchos podrían beneficiarse de innovar a alto nivel, como unir un programa de imágenes que solo usa bibliotecas de funciones de procesamiento de imágenes existentes ya implementadas en C, donde no están innovando tanto en el nivel más bajo de bucle a través de píxeles individuales, pero tal vez ofreciendo una interfaz de usuario muy amigable y un flujo de trabajo nunca antes visto. En ese caso, si el objetivo del software es simplemente hacer llamadas de alto nivel en bibliotecas de bajo nivel ( "procesar esta imagen completa para mí, no para cada píxel, hacer algo" ), podría decirse que podría ser una optimización prematura incluso intentar comenzar a escribir dicha aplicación en C.

Pero si está haciendo algo nuevo en el nivel bajo donde ayuda a acceder a los datos de un nivel bajo como un filtro de imagen nuevo nunca antes visto que sea lo suficientemente rápido como para trabajar en video HD en tiempo real, entonces generalmente debe obtener Un poco peligroso.

Es fácil dar esto por sentado. Recuerdo una publicación de Facebook con alguien señalando cómo es factible crear un videojuego 3D con Python con la implicación de que los lenguajes de bajo nivel se están volviendo obsoletos, y ciertamente era un juego de aspecto decente. Pero Python estaba haciendo llamadas de alto nivel a bibliotecas implementadas en C para hacer todo el trabajo pesado. No puede hacer Unreal Engine 4 simplemente haciendo llamadas de alto nivel a las bibliotecas existentes. Unreal Engine 4 esla biblioteca. Hizo todo tipo de cosas que nunca existieron en otras bibliotecas y motores, desde la iluminación hasta su sistema de planos nodales y cómo puede compilar y ejecutar código sobre la marcha. Si desea innovar en el tipo de bajo nivel de motor / núcleo / núcleo, entonces debe obtener un nivel bajo. Si todos los desarrolladores de juegos cambiaran a idiomas seguros de alto nivel, no habría Unreal Engine 5, 6 o 7. Es probable que las personas sigan usando Unreal Engine 4 décadas después porque no se puede innovar en el nivel requerido para llegar con un motor de próxima generación simplemente haciendo llamadas de alto nivel al viejo.


fuente