¿C++ es adecuado para sistemas embebidos?

Una pregunta común, aquí y en otros lugares. ¿C++ es adecuado para sistemas embebidos?

¿Microcontroladores? ¿RTOS? ¿Tostadoras? PC integradas?

¿Es OOP útil en microcontroladores?

¿C++ aleja demasiado al programador del hardware para ser eficiente?

¿Debería considerarse el C++ de Arduino (sin administración de memoria dinámica, plantillas, excepciones) como "C++ real"?

(Con suerte, esta wiki servirá como un lugar para contener esta potencial guerra santa)

Pregunta rápida: cuando dice integrado , ¿quiere decir microcontrolador? ¿microprocesador? x86 integrado/PC integrado?
C++ vs incrustado es un tema polémico. Tengo una opinión fuerte, pero no me pareció justo plantear una pregunta y jugar a sumar puntos. Espero que un wiki de la comunidad genere una discusión más equilibrada.
Entendí por qué lo hiciste, baso mis opiniones en lo que permite que un trabajo se haga bien y rápido, pero la mayoría de las personas que conozco lo consideran un tema candente y fácilmente se ponen rojos.
Estoy de acuerdo con @Joby, esta es una Wiki comunitaria 100% clara...
sí, leí mal algo y pensé que alguien más era el cartel original. Mala mía, aclarando mis comentarios.
Esta es una mala pregunta ya que "incrustado" es un atributo sin sentido para decidir si un idioma en particular y su equipaje asociado son adecuados. El punto es sistemas pequeños versus grandes, donde los sistemas pequeños no ejecutan un sistema operativo, tienen memoria limitada, pueden no ser von Neuman, pueden tener varias restricciones de hardware en pilas de llamadas, pilas de datos, no puede simplemente asignar dinámicamente un Mb o incluso un kb, etc. La mayoría de los microcontroladores son sistemas "pequeños". Las computadoras de placa única generalmente están integradas, pero generalmente son sistemas "grandes".
La pregunta parece implicar "c++=OOP". Esto no es cierto en absoluto, C ++ es un lenguaje de múltiples paradigmas, puede hacer OOP, procedimientos estrictos, funcionales, ¡lo que sea!

Respuestas (16)

Sí, C++ sigue siendo útil en sistemas integrados. Como todos los demás han dicho, todavía depende del sistema en sí, como un uC de 8 bits probablemente sería un no-no en mi libro a pesar de que hay un compilador y algunas personas lo hacen (estremecimiento). Todavía hay una ventaja en el uso de C ++, incluso cuando lo reduce a algo como "C +", incluso en un micromundo de 8 bits. ¿Qué quiero decir con "C+"? Me refiero a no usar new/delete, evitar excepciones, evitar clases virtuales con herencia, posiblemente evitar la herencia por completo, tener mucho cuidado con las plantillas, usar funciones en línea en lugar de macros y usar constvariables en lugar de #defines.

He estado trabajando tanto en C como en C++ en sistemas integrados durante más de una década, y parte de mi entusiasmo juvenil por C++ definitivamente se ha desvanecido debido a algunos problemas del mundo real que sacuden la ingenuidad de uno. He visto lo peor de C ++ en sistemas integrados a los que me gustaría referirme como "programadores de CS enloquecidos en un mundo EE". De hecho, eso es algo en lo que estoy trabajando con mi cliente para mejorar este código base que tienen entre otros.

El peligro de C++ se debe a que es una herramienta muy, muy poderosa, como una espada de dos filos que puede cortarle un brazo y una pierna si no se educa y se disciplina adecuadamente en su lenguaje y en la programación general. C es más como una espada de un solo filo, pero igual de afilada. Con C++ es demasiado fácil obtener niveles muy altos de abstracción y crear interfaces ofuscadas que pierden sentido a largo plazo, y eso se debe en parte a la flexibilidad de C++ para resolver el mismo problema con muchas funciones de lenguaje diferentes (plantillas, programación orientada a objetos, procedimientos, RTTI, OOP+plantillas, sobrecarga, en línea).

Terminé dos seminarios de 4 horas sobre software integrado en C++ impartidos por el gurú de C++, Scott Meyers. Señaló algunas cosas sobre las plantillas que nunca antes había considerado y cuánto más pueden ayudar a crear código crítico para la seguridad. El quid de la cuestión es que no se puede tener código inactivo en un software que tiene que cumplir estrictos requisitos de código críticos para la seguridad. Las plantillas pueden ayudarlo a lograr esto, ya que el compilador solo crea el código que necesita al crear instancias de plantillas. Sin embargo, uno debe educarse más a fondo en su uso para diseñar correctamente esta función, que es más difícil de lograr en C porque los enlazadores no siempre optimizan el código muerto.

Scott Meyers es un gran defensor de las plantillas y el uso sensato de la inserción, y debo decir que todavía soy escéptico acerca de las plantillas. Tiendo a alejarme de ellos, aunque él dice que solo deben aplicarse donde se conviertan en la mejor herramienta. También destaca que C++ le brinda las herramientas para crear interfaces realmente buenas que son fáciles de usar correctamente y dificultan su uso incorrecto. Una vez más, esa es la parte difícil. Uno debe llegar a un nivel de dominio en C++ antes de poder saber cómo aplicar estas características de la manera más eficiente para ser la mejor solución de diseño.

Lo mismo ocurre con la programación orientada a objetos. En el mundo integrado, debe familiarizarse con el tipo de código que arrojará el compilador para saber si puede manejar los costos de tiempo de ejecución del polimorfismo en tiempo de ejecución. También debe estar dispuesto a realizar mediciones para demostrar que su diseño cumplirá con los requisitos de su fecha límite. ¿Esa nueva clase InterruptManager hará que mi latencia de interrupción sea demasiado larga? Hay otras formas de polimorfismo que pueden adaptarse mejor a su problema, como el polimorfismo en tiempo de enlace, que C también puede hacer, pero C ++ puede hacerlo a través del patrón de diseño Pimpl (puntero opaco) .

Digo todo eso para decir que C++ tiene su lugar en el mundo integrado. Puedes odiarlo todo lo que quieras, pero no va a desaparecer. Se puede escribir de una manera muy eficiente, pero es más difícil aprender cómo hacerlo correctamente que con C. A veces puede funcionar mejor que C para resolver un problema y, a veces, expresar una mejor interfaz, pero nuevamente, tienes que infórmate y no tengas miedo de aprender cómo hacerlo.

Esto va en línea con lo que he leído de otros consultores de sistemas integrados. Siempre me han enseñado que con C, te cortas a ti mismo en pequeñas formas constantemente, pero un error en C ++ será más raro, pero cuando te equivoques, perderás una pierna. Gracias por escribir una respuesta clara con cierta experiencia que no tengo.
Me informaron que realmente necesita pasar tiempo y capacitarse en las técnicas adecuadas antes de lanzarse de cabeza a C ++.
Sobre la nota de que los estudiantes de Ciencias de la Computación se están volviendo locos en la tierra de EE. En mi trabajo, el peor código que tenemos fue escrito por un especialista en informática. Pasamos una eternidad tratando de enseñarle qué era el hardware. Hizo un sistema estructurado usando UML y construyó todo el sistema basado en él en Java usando la herencia adecuada, etc. Funcionó, hasta que algo cambió, y luego fue un mal trabajo de parche para agregar funciones o un rediseño completo. El código casi no se puede usar debido a lo bien que ofuscó todo con la herencia.
No son solo los errores los que te pican, sino también el código que no se puede mantener. Claro, cuando comienzas ese proyecto usando esas características ordenadas de C ++, todo sale a la perfección, pero después de 2 o 3 años, la entropía se activa si no se hace un esfuerzo serio en la refactorización a medida que desarrollas. Eso es a lo que me enfrento en este momento... el código se pudre más rápido con el tiempo en C++.
UML y máquinas de estado. Realmente necesita mirar las cosas de Miro Samek en state-machine.com . Ha construido un sistema eficiente que es fácil de refactorizar y cambiar, pero lleva algo de tiempo asimilarlo.
Eso es lo que nos mató en Java DoxaLogos. Y para nosotros, los errores de tiempo de ejecución son un problema y en la mayor parte de nuestro mantenimiento tenemos la posibilidad de errores de tiempo de ejecución porque nuestro sistema está funcionando más allá del punto de carga del 95%.
@Kortuk: un comentario más sobre "cargar de cabeza en C ++". Estoy de acuerdo en que, idealmente, desea dedicar tiempo a aprender primero C ++ antes de cargar de cabeza, pero a veces no funciona de esa manera. En mi empleador anterior, tuvimos una situación en la que elegimos el código de otra división escrito en C ++ por sus características, pero todo el piso era un grupo de EE que en su mayoría conocían C. Yo era uno de los pocos que tenía algo de entrenamiento en C ++ en el tiempo, pero no mucho. Puedes imaginar el caos que siguió :-)
@Doxa, sí puedo. He estado comprando libros y tratando de darme la mayor capacitación posible antes de comenzar con cualquier sistema nuevo.
@Kortuk. Estoy seguro de que puedes, y me alegro de que tengas la previsión de hacerlo. Es por eso que comencé a aprenderlo yo mismo en la universidad mientras mi título era EE. Mi punto era que a veces no funciona de esa manera. Todos esos ingenieros ahora tenían que trabajar en un entorno C ++ sin ningún tipo de capacitación debido al continuo "tiempo de comercialización". El error fue del lado de la gerencia, por supuesto, y no su culpa.
@doxa, sí, el tipo antes que yo era muy apto e hizo un gran trabajo. Su código es inutilizable debido al ridículo tiempo de implementación y el avance de funciones que tuvo que hacer modificaciones para mantener la cabeza fuera del agua. Todo lo que puedo hacer es luchar y, a veces, aceptar las consecuencias.
@DoxaLogos: dice que evitar las funciones de herencia/virtuales es algo bueno. ¿Puede explicar a qué se refiere? ¿Esta idea excluye la posibilidad de escribir clases en una interfaz de clase base abstracta?
Realmente depende de su sistema y de la cantidad de memoria que tenga disponible. ¿Estás escribiendo código en un micro de 8 bits con muy poca memoria RAM? Entonces es mejor que evite volverse loco con las interfaces abstractas. Si está escribiendo algo así como sistemas integrados de 32 bits con bloques de memoria, hágalo. Realmente tienes que sopesarlo. Por ejemplo, cada vez que coloca el mundo "virtual" en esa clase, obtiene un puntero adicional, que podría ser de 8 bits, 16 bits o 32 bits según el sistema, para cada instancia que declare de ese objeto. Ni siquiera te darás cuenta, y hombre,
¿Me mordió ese? Probablemente no debería haber dicho evitar, sino más bien asegurarme de que realmente lo necesitas en el diseño. El problema con C ++ es cómo "oculta" la cantidad de memoria que usa, en comparación con mirar el código C directo, y ni siquiera me refiero a la biblioteca STL, que absorberá RAM rápidamente cuando esté en uso.
disculpe... asegúrese de que realmente lo necesita y puede PAGARLO en su diseño.
¿Podemos entonces resumirlo todo y decir que en C++ es mucho más fácil sobrediseñar las cosas que en C?
Basándome en algunos resultados de Google, decidí ver cómo funcionaría C++ en MSP430. "Hola mundo" falla, lo cual es vergonzoso. Necesita 128kB de FRAM para compilar, ya que la biblioteca iostream aparentemente es demasiado monolítica o algo así. En cualquier caso, eso demuestra que las cosas pueden fallar desde el principio.
C ++ tiene algunas características realmente geniales (lo uso bastante, depende del proyecto), pero una cosa que debe tenerse en cuenta es la disciplina requerida para no abstraer demasiado las cosas; eso puede ser un problema importante para el mantenimiento.
"como una espada de dos filos que puede cortarte el brazo y la pierna" - Esto también se aplica a C.
@Kortuk, On the note of Computer Science majors going crazy in EE land ...--> Érase una vez algunos consultores profesionales de CS con nosotros que tenían muchos años de experiencia y estaban convencidos de que programar sin excepciones es simplemente nauseabundo. Habilitaron excepciones con -fexceptionslos controladores integrados (lo cual fue desaconsejado activamente por el fabricante de esos controladores), mientras se quejaban de que la gente de EE simplemente no entendía el software y lanzaba excepciones de cualquier manera. (-‸ლ) Después de un par de años en el infierno de desarrollo, el proyecto murió.

C++ es absolutamente adecuado para sistemas integrados. Ahora uso la presencia/ausencia de buenas herramientas de desarrollo (o la falta de ellas) como mi criterio principal para usar o no un microprocesador en particular.

Áreas de C ++ que son buenas para usar en sistemas integrados porque tienen bajos costos de recursos:

  • modularidad aportada por el buen uso de clases/estructuras
  • plantillas si el compilador hace un buen trabajo al compilarlas de manera eficiente. Las plantillas son una buena herramienta para llevar la reutilización de algoritmos a diferentes tipos de datos.

Áreas aceptables:

  • funciones virtuales: solía estar en contra de esto, pero el costo del recurso es muy pequeño (una vtable por clase , no por objeto; un puntero a la vtable por objeto; una operación de desreferenciación por llamada de función virtual) y la gran ventaja de esto es que le permite tener una matriz que contiene varios tipos diferentes de objetos sin tener que saber de qué tipo son. Usé esto recientemente para tener una matriz de objetos, cada uno representando un dispositivo I2C, cada uno con métodos separados.

Áreas que no se deben usar, principalmente debido a la sobrecarga de tiempo de ejecución que es inaceptable en sistemas pequeños:

  • asignación de memoria dinámica: otros han mencionado esto, pero otra razón importante para no usar la asignación de memoria dinámica es que representa incertidumbre en el tiempo; muchas razones para usar sistemas embebidos son para aplicaciones en tiempo real.
  • RTTI (información de tipo de tiempo de ejecución): el costo de la memoria es bastante alto
  • excepciones: un rotundo no-no, debido al golpe de velocidad de ejecución
En realidad, la asignación de memoria dinámica está bien y, a veces, es inevitable. El problema es la asignación dinámica de memoria (y la posterior reutilización). RTTI acapara la memoria, estoy de acuerdo con eso. Pero, ¿cuál es el problema con las excepciones?
@WoutervanOoijen: El problema con las excepciones es que si foollama bardentro de un bloque try/ y crea algunos objetos y llama , lo que genera una excepción, el sistema tiene que llamar de alguna manera a los destructores de los objetos creados antes de devolver el control a . A menos que las excepciones estén completamente deshabilitadas, no tendrá forma de saber si podría arrojar alguna y, por lo tanto, debe incluir código adicional para permitir esa posibilidad. Me gustaría ver una variación de C++ con "excepciones marcadas" para lidiar con eso; si las rutinas que podrían permitir el escape de excepciones... catchbarbozbarfoobarboz
... tenía que declararse como tal, entonces solo sería necesario que el compilador incluyera código de manejo de excepciones en las llamadas de tales rutinas. Sin duda, tener que agregar todas las declaraciones requeridas y, con suerte, evitar las innecesarias, sería algo engorroso, pero permitiría usar excepciones en lugares donde son útiles, sin agregar sobrecarga donde no lo son.
@WoutervanOoijen: Por cierto, si estuviera diseñando la ABI para tal manejo de excepciones en ARM, especificaría que el código que llama a una rutina que puede salir a través de una excepción debería tener R14 apuntando a una dirección dos bytes antes de la dirección de retorno deseada (esto sería ocurren naturalmente si la persona que llama siguió la instrucción CALL con una palabra de 16 bits). La rutina llamada saldría normalmente a través add r15,r14,#2de en lugar de mov r15,r14; para salir por excepción, ldrhs r0,[r14] / add r15,r14,r0. Costo de ciclo cero para la salida normal y sin restricciones de marco de pila.
Por lo tanto, el problema con las excepciones es que la implementación actual pone una carga no despreciable en el caso de no excepción. Esto hace que las excepciones sean impopulares, por lo que los implementadores no sienten la necesidad de hacerlo más eficiente :( Nunca he estudiado los detalles de las devoluciones de excepciones, pero intuitivamente esperaba algo como lo que describe.
@WoutervanOoijen: Lo tienes. El manejo de excepciones debe habilitarse o deshabilitarse globalmente; si está habilitado para el 1% del código, hace que todo el código sea menos eficiente en espacio y, por lo general, más lento. En cuanto a si los implementadores quieren hacerlo más eficiente, entran en juego problemas de compatibilidad. Entre otras cosas, permitir que las excepciones pasen a través de código C o ensamblador requiere que el throwcódigo pueda encontrar el catch, ya sea requiriendo que el código C o ensamblador siga un estricto protocolo de marco de pila, o bien utilizando una ubicación estática para contener la información necesaria o un puntero a ella.
@WoutervanOoijen: dado que el código existente que no es C++ puede no ajustarse a ningún protocolo de apilamiento en particular, y dado que un conmutador de tareas debe conocer todas y cada una de esas ubicaciones estáticas e intercambiarlas al cambiar de tareas, no es posible cambiar cómo funciona el manejo de excepciones sin requerir que se reescriba algún código no relacionado con excepciones.
Creo que no está 'reescrito' sino solo 'recompilado con el mismo compilador de C++'.
@WoutervanOoijen: Me refiero a "reescrito". El código escrito en C++ no sería el problema. Si en un sistema multitarea, una rutina de C++ foollama a la rutina de lenguaje ensamblador bar, que coloca elementos arbitrarios desconocidos en la pila antes de llamar a la rutina bozde C++ y bozlanza una excepción, el sistema de alguna manera tiene que encontrar fooel marco de la pila. No hay forma de que eso suceda sin modificar la rutina del lenguaje ensamblador barpara que su valor inicial de puntero de pila esté disponible para el código que está llamando, o modificar el multitarea para guardar/restaurar un puntero de marco de excepción estático.
@WoutervanOoijen ¿Cuál es el costo de memoria de RTTI?
@supercat " permitir que las excepciones pasen a través de C o el código ensamblador " es intrínsecamente poco confiable ya que ese código no está preparado para tal caso y puede dejar basura alrededor
El costo de memoria de RTTI es cierta información almacenada en flash sobre las clases en su aplicación. En mi opinión, este no es un gran costo, pero los casos de uso de RTTI (principalmente dowcasts) me parecen poco atractivos de todos modos, entonces, ¿por qué no evitar el costo?
@curiousguy: Tienes razón en que si algún código de paso requiere limpieza, tendría que saber sobre cualquier medio por el cual el control podría escapar. Mi punto es que el hecho de no usar marcos de pila desenrollables plantearía un problema en las implementaciones que no pueden usar el almacenamiento estático de subprocesos, incluso en los casos en que el código que no es de C++ no necesitaba hacer ninguna limpieza.

Sí, C++ ciertamente es adecuado para sistemas integrados. Primero aclaremos un par de conceptos erróneos sobre la diferencia entre C y C++:

En un micro incrustado, siempre necesitará usar lenguajes de alto nivel con cuidado si le preocupan las limitaciones de tiempo o espacio. Por ejemplo, muchas MCU no manejan bien los punteros y, por lo tanto, son muy ineficientes cuando usan la pila. Esto significa que debe tener cuidado al pasar variables a funciones, usar matrices y punteros y recursividad. Una simple línea de C como:

a[i] = b[j] * c[k];

puede generar alrededor de 4 páginas de instrucciones dependiendo de la naturaleza de esas variables.

Cada vez que utiliza un lenguaje de alto nivel y le preocupan las limitaciones de tiempo y espacio, necesita saber cómo cada función de ese lenguaje se traduce en instrucciones de máquina en su MCU (al menos, cada función que usa). Esto es cierto para C, C++, Ada, lo que sea. Probablemente todos los idiomas contengan funciones que no se traducen de manera eficiente en MCU pequeños. Siempre verifique las listas de desensamblaje para asegurarse de que el compilador no esté generando montones de instrucciones para algo trivial.

¿C es adecuado para MCU integrados? Sí, siempre y cuando vigiles el código generado.
¿C++ es adecuado para MCU integrados? Sí, siempre y cuando vigiles el código generado.

He aquí por qué creo que C++ es mejor que C incluso en MCU de 8 bits: C++ brinda soporte mejorado para:

  • ocultación de datos
  • Escritura/comprobación más fuertes
  • Transparencia multiperiférica usando clases
  • Plantillas (como siempre si se usan con cuidado)
  • Listas de inicialización
  • constante

Ninguna de estas características es más pesada que las características típicas de C.

A medida que avanza a MCU de 16 o 32 bits, entonces comienza a tener sentido usar características más pesadas de C (pila, montón, punteros, matrices, printf, etc.) De la misma manera, en una MCU más potente se vuelve apropiado para usar características más pesadas de C++ (pila, montón, referencias, STL, nuevo/eliminar).

Por lo tanto, no hay necesidad de estremecerse al pensar en C++ en un PIC16. Si conoce su idioma y su MCU correctamente, entonces sabrá cómo usarlos juntos de manera efectiva.

" a[i] = b[j] * c[k];puede generar alrededor de 4 páginas de instrucciones dependiendo de la naturaleza de esas variables". Si su MCU/compilador hace esto, es porque está usando una CPU de aficionado de garaje de los años 80.
@Lundin - Suspiro. No, significa que está utilizando una pequeña MCU barata que está diseñada para ser lo más pequeña y económica posible, no para tener cosas complejas como la indexación de pila.
@Rocketmagnet Ok, ¿quizás en la década de 1990? Hoy en día, los 8 amargos de mierda tienen el mismo precio que los 32 amargos. La única razón que queda para elegir el primero es el consumo actual. Y con respecto a esos 8 bits extra-mierdos sin pila: si escribe C en lugar de ensamblador para una MCU tan limitada, es probable que lo esté haciendo mal. Las 4 páginas generadas son culpa suya por escribir programas demasiado complejos para la CPU, y esencialmente C es la herramienta incorrecta para la tarea. (Hice esto en el pasado en Freescale RS08, fue una idea muy estúpida).
El procesador @Lundin de 32 bits no es necesario más rápido que 16 bits. Esto fue evidente en el pasado, cuando la transición del programa de 16 a 32 bits estaba ocurriendo en el mundo de la PC.
@Barleyman Hay otras preocupaciones además de la velocidad que hacen que 8 y 16 bits sean una mala elección, sobre todo la incapacidad de abordar convenientemente más de 65 kb de memoria. Pero también los diversos problemas del lenguaje C que tienden a surgir para MCU tan pequeños, como errores de promoción de enteros implícitos. Además, casi todas las arquitecturas de 8 bits del mercado tienen un núcleo absolutamente horrible que se originó en los años 70 y 80. Incluye: foto, 8051, HC08, AVR.
@Lundin Tengo mayor experiencia con MSP430, que es una arquitectura de 16 bits. No compararía eso con 8051 o algo así, es una bestia completamente diferente. ¡¿Y por qué necesitaría más de 64kB de memoria si esa µCU solo tiene 64kB?! En serio, pensó, tiene direccionamiento de 20 bits y ese es un arreglo bastante común, de verdad. FRAM es realmente agradable en comparación con FLASH. RAM no volátil de acceso aleatorio real. Mi principal queja es que no hace DIV, lo que significa que tienes que hacer todo lo posible para evitar divisiones. De todos modos, Texas tiene excelente soporte y documentación, por lo que es una gran ventaja sobre, por ejemplo, ST Micro.

Siempre encuentro estos debates entretenidos de leer. No tanto por la discusión intelectual sobre los pros y los contras de los distintos idiomas disponibles, sino porque normalmente puedes fijar la postura de alguien sobre el tema en función de su trabajo/experiencia/área de interés. Está a la altura de los argumentos de "optimización prematura" donde los programadores de mantenimiento y especialistas en informática citan a Knuth de izquierda a derecha y aquellos que trabajan en el mundo real donde el rendimiento importa piensan que están todos locos (soy miembro del último grupo para ser justo).

Al final del día, puede desarrollar un software excelente en C o C++ o insertar lenguaje aquí . Todo se reduce a las capacidades del desarrollador, no al lenguaje. Por lo general, solo se requiere ser un experto en un idioma si ha elegido el idioma incorrecto para empezar y ahora necesita modificarlo para resolver su problema; en la mayoría de los casos, estas son las únicas situaciones en las que necesita sumergirse en características oscuras o compilador. Trucos para lograr el objetivo.

A menudo escucho a la gente comenzar estos argumentos como "Soy un experto en lenguaje X y bla, bla". Sinceramente, desacredito inmediatamente a estas personas porque, en mi opinión, ya han abordado el problema desde el ángulo equivocado y todo lo que sigue está viciado. por su deseo de usar su herramienta para resolver el problema y mostrar lo "genial" que es.

Muy a menudo observo a los desarrolladores elegir primero un conjunto de herramientas e intentar adaptarlo a su problema en segundo lugar, lo que es completamente incorrecto y da como resultado soluciones de mierda.

Como mencioné en un comentario a otra respuesta, estas guerras de idiomas a menudo se convierten en argumentos de que el lenguaje X le permite al programador hacer cosas más tontas. Si bien es entretenido leer, todas estas declaraciones realmente significan que tiene un problema para contratar buenos desarrolladores y necesita abordar ese problema directamente en lugar de tratar de curar la situación al continuar contratando a malos desarrolladores y eligiendo herramientas para que puedan hacer lo menos posible. daño como sea posible.

En mi opinión, los buenos desarrolladores, ya sea desarrollo de software o hardware, investigan el problema, diseñan una solución y encuentran las herramientas que les permiten expresar la solución de la 'mejor manera'. No debería importar si la herramienta requerida es algo que nunca ha usado antes, después de haber usado 3 o 4 idiomas/herramientas de desarrollo para proyectos, seleccionar una nueva debería tener un impacto mínimo en su tiempo de desarrollo.

Por supuesto, 'la mejor manera' es un término subjetivo y también debe definirse en la fase de investigación. Uno debe considerar una multitud de cuestiones: rendimiento, facilidad de expresión, densidad de código, etc. en función del problema en cuestión. No incluí la mantenibilidad en esa lista por una razón, no me importa qué idioma elija, si eligió la herramienta adecuada y se tomó el tiempo para comprender el problema, esto debería ser 'gratis'. El código difícil de mantener es a menudo el resultado de elegir la herramienta incorrecta o una estructura de sistema deficiente, lo que resulta en un feo desorden para que funcione.

Afirmar que cualquier idioma es 'mejor' que cualquier otro es una tontería sin definir un problema de interés particular. Un enfoque orientado a objetos no siempre es mejor que un enfoque funcional. Hay algunos problemas que se prestan muy bien a un paradigma de diseño orientado a objetos. Hay muchos que no. Se puede hacer la misma afirmación acerca de muchas características del lenguaje sobre las que la gente parece disfrutar insistiendo.

Si dedica más del 20% de su tiempo a un problema escribiendo código, probablemente esté produciendo un sistema muy deficiente, o tenga desarrolladores muy deficientes (o todavía esté aprendiendo). Debería pasar la mayor parte de su tiempo al principio diagramando el problema y determinando cómo interactúan varias piezas de la aplicación. Poner a un grupo de desarrolladores talentosos en una sala con un marcador y un problema para resolver y decirles que no pueden escribir ningún código o elegir ninguna herramienta hasta que se sientan cómodos con todo el sistema contribuirá más a mejorar la calidad del rendimiento y velocidad de desarrollo que elegir cualquier herramienta nueva y novedosa garantizada para mejorar el tiempo de desarrollo. (busque el desarrollo de scrum como referencia para el polo opuesto a mi argumento)

A menudo, la desafortunada realidad es que muchas empresas solo pueden medir el valor de un desarrollador por la cantidad de líneas escritas o por ver 'resultados tangibles'. Ven las 3 semanas en una habitación con un marcador como una pérdida de productividad. Los desarrolladores a menudo se ven obligados a acelerar la etapa de "pensamiento" del desarrollo o se ven obligados a usar un conjunto de herramientas por algún problema político dentro de la empresa, "El hermano de mi jefe trabaja para IBM, así que solo podemos usar sus herramientas", ese tipo de basura. . O peor aún, obtiene un conjunto de requisitos en constante cambio de la empresa porque no son capaces de realizar una investigación de mercado adecuada o no comprenden el impacto de los cambios en el ciclo de desarrollo.

Perdón por estar un poco fuera de tema con esta diatriba, tengo opiniones bastante fuertes sobre este tema.

+1, lo disfruté, aunque un poco largo. Solo uso C en el trabajo, pero realmente estoy tratando de cambiarme a C++ porque hay muchas bonificaciones. Tengo mis prejuicios, principalmente debido a lo que salió mal o al hecho de que tengo un jefe que cambia las especificaciones dentro de los 2 días posteriores a decirnos lo que se necesita. Todavía estoy aprendiendo, y espero sentirme así durante unos 4 o 5 años más. Todavía aprenderé después de ese punto, pero mi empresa no tiene una guía de estilo que se siga o un proceso de inspección y estoy tratando de obtener ambos.
Creo que diste en el clavo con tu comentario sobre doblar la herramienta alrededor del problema. Me recuerda el dicho: "Cuando todo lo que tienes es un martillo, todo parece clavo". ¿Fue un juego de palabras? ;-) TDD definitivamente va en contra del pensamiento inicial, y no creo que alguna vez me sienta cómodo con la idea de hacer pruebas para crear el diseño... especialmente en sistemas integrados. ¿Cómo diablos puede simular una pieza de hardware para probar un controlador de dispositivo sin perder mucho tiempo en la pieza simulada?
Ahora, no estoy eliminando pruebas unitarias en un nivel de aplicación (por encima del controlador) en ciertos sistemas integrados. Hay cierto valor en la retroalimentación instantánea de las pruebas unitarias y la eliminación de errores al principio de la fase de desarrollo, pero todo el paradigma TDD para dar a luz al diseño me parece un poco tonto. Prefiero tomarme un tiempo para "pensar" sobre el problema y diagramarlo en mi cabeza, en papel o en una pizarra, antes de comenzar a codificar. También creo que TDD alienta al mercado a no realizar una investigación inicial sobre los requisitos, porque se supone que debe ayudar con el cambio constante de requisitos.
Y para poner una nota final a mi comentario súper largo... No necesitamos expertos en idiomas para trabajar el diseño. Necesitamos diseñadores expertos que puedan trabajar los idiomas.
Perdón por la diatriba épicamente larga, tiendo a ponerme bastante frenético cuando veo un tema que se debate mucho cuando lo veo como un simple resultado de un problema más profundo que creo que debería ser el verdadero tema de discusión.
@doxalogos El punto TDD es bueno. El único problema que tuve en mi experiencia, ciertamente limitada, con empresas que fuerzan estos problemas es que requieren un TDD pero no están dispuestos a producir un PRD firme.
@doxalogos err, lo siento, confundí TDD con TRD, demasiados TLA (acrónimos de tres letras)
@mark, ¿puedes definir PRD y TRD?
PRD = documento de requisitos del producto, MRD = documento de requisitos de comercialización, TRD = documento de requisitos técnicos. TDD = Desarrollo dirigido por pruebas.
@doxalogos, la idea de TDD (Test Driven Development) es interesante, pero creo que es inherentemente defectuosa. Estoy 100% de acuerdo con todo lo que dices al respecto. En cuanto a las pruebas unitarias, he leído historias de empresas que, al implementar un proceso de inspección de software bien desarrollado, podrían descartar las pruebas unitarias y ahorrar tiempo para el lanzamiento.
@DoxaLogos, Gracias por las definiciones, mi empresa es pequeña, conocía TDD, pero eso fue todo.
@Mark: estoy de acuerdo con sus sentimientos de diseño por adelantado, pero solo hasta cierto punto. Creo que los trabajos pesados ​​de diseño por adelantado valen la pena si a) sus requisitos son bastante estables/conocidos, yb) los desarrolladores que realizan el diseño tienen experiencia . En un anterior. trabajo, me dieron la tarea de hacer un diseño y el líder de mi equipo me restringió mucho el tiempo, y pensé: "¡Qué tontería! ¿¿El diseño por adelantado ahorra dinero (cf. libro Code Complete)?" Pero en la codificación descubrí toneladas de cosas que no sabía buscar. Si hubiera hecho mucho diseño y minimizado el tiempo de código, habría sido un desperdicio. JME.
@sheepsimulator Obviamente estoy de acuerdo con el segundo punto, supongo que los arquitectos principales del sistema son desarrolladores experimentados. En el primer punto, en realidad no estoy de acuerdo. Creo que cuanto más espera que cambien los requisitos, más tiempo debe pasar en la fase de diseño porque necesita producir un diseño bueno y fácil de cambiar. Sé que algunas filosofías proponen un desarrollo rápido. En algunos casos esto funciona bien como muchos programadores malos o sin experiencia en el personal. Todas estas filosofías de diseño se reducen a decir "no tengo ningún deseo de diseñar un sistema flexible, así que no perdamos el tiempo intentándolo".
Nuestros requisitos están cambiando todo el tiempo aquí, pero los sistemas que dedicamos más tiempo a diseñar tienen el tiempo de codificación y mantenimiento más rápido. Dedicamos una gran cantidad de tiempo a un subsistema porque sabemos lo importante que sería en el futuro y que tendría que cambiar. Es el único subsistema en el que cualquier cambio ha significado menos de un día de trabajo, y ha tenido muchos.

En mi experiencia, C ++ generalmente no se adapta a los pequeños sistemas integrados. Con lo que quiero decir, microcontroladores y dispositivos sin sistema operativo.

Muchas técnicas de programación orientada a objetos de C++ se basan en la asignación de memoria dinámica. Esto a menudo falta en los sistemas pequeños.

STL y Boost realmente demuestran el poder de C++, ambos ocupan un espacio enorme.

C++ anima al programador a abstraerse de la máquina, donde en sistemas restringidos tiene que ser adoptada.

El año pasado, transfirí un producto comercial de escritorio remoto a teléfonos móviles. Fue escrito en C++ y se ejecutó en Windows, Linux y OSX. Pero dependía en gran medida de STL, memoria dinámica y excepciones de C++. Para ponerlo en marcha en entornos WinCE, Symbian y sin sistema operativo, una reescritura de C era la opción más sensata.

Estoy de acuerdo en referencia a los sistemas pequeños, pero creo que tenemos diferentes definiciones de sistemas pequeños. Cuando tiene 1kB de ROM y un código C bien escrito toma todo menos 1 byte de ROM, ese es un sistema pequeño.
No estoy argumentando que C no puede tener una huella más pequeña, pero aún podría haber usado C ++ y obtenido un resultado muy similar para diseñar lo que se acaba de discutir. Creo que el problema es que la mayoría de los programadores OOP están acostumbrados a sistemas con memoria dinámica y usan construcciones muy ineficientes, lo que resulta en un código completamente inútil para sistemas de menor potencia.
He realizado principalmente desarrollo SBC x86 a gran escala en C++, por lo que me resulta útil escuchar experiencias (positivas o negativas) sobre el uso de C++ en plataformas con menos recursos.
He hecho una gran cantidad de desarrollo en computadoras con C++, no he hecho casi nada en plataformas integradas. He realizado una gran cantidad de desarrollo en plataformas integradas, y me refiero a la gama de MSP430 y PIC. Todo esto se ha hecho en C. No hay bibliotecas ni nada. Me gustaría usar C++ en un proyecto de sistemas integrados, hay muchas buenas razones, hasta ahora no he escuchado razones que no puedan resolverse usando reglas estrictas sobre qué construcciones de C++ pueden usarse.
entonces lo que dices es que no quieres usar C++, quieres usar algo entre C y C++ (¿vamos a llamarlo C+?). En ese caso, estoy de acuerdo, hay mucha basura en C++ que la gente usa solo porque está disponible, no porque sea óptimo. Casi cualquier lenguaje es capaz de producir código bueno y rápido, depende de cómo se use. La mayoría de las guerras santas por los idiomas no son el resultado de las capacidades de los idiomas, sino una discusión sobre lo fácil que es para un idiota hacer cosas idiotas, que en realidad es un argumento idiota: p
Trato de discutir sobre cuán poderoso es un lenguaje para hacer las cosas. Creo que C++ da grandes pasos agigantados en el poder para hacer las cosas. Con un diseño e implementación adecuados, veo grandes mejoras en la forma en que desarrollamos los sistemas, que es lo que quiero, y si puede ayudar a otros, pero solo requiere un poco más de capacitación, entonces estoy interesado.
Sin embargo, tampoco uso la memoria dinámica en C. No hay ningún lugar donde deba tenerlo. A largo plazo, he leído que puede segmentarse mucho y comenzar a causar problemas. Necesito tener casos muy claramente diseñados para quedarse sin memoria, y necesito poder monitorear exactamente cuánto queda.

Cualquier lenguaje puede ser adecuado para un sistema embebido. Embebido solo significa: parte de un aparato más grande, a diferencia de una computadora de uso gratuito.

La pregunta tiene más relevancia cuando se pregunta por un sistema de recursos limitados o en tiempo real (duro) .

Para un sistema en tiempo real, C ++ es uno de los lenguajes más avanzados que aún es apropiado cuando se programa para restricciones de tiempo estrictas. Con la excepción del uso del montón (operador libre), no tiene construcciones que tengan un tiempo de ejecución indeterminado, por lo que puede probar si su programa cumple con los requisitos de tiempo y, con un poco más de experiencia, incluso podría predecirlo. Por supuesto, se debe evitar el uso del almacenamiento dinámico, aunque el nuevo operador aún se puede usar para una asignación única. Las construcciones que C++ ofrece sobre C se pueden utilizar en un sistema integrado: OO, excepciones, plantillas.

Para sistemas con recursos muy limitados (chips de 8 bits, menos de unos pocos Kb de RAM, pila no accesible), C++ completo podría no ser adecuado, aunque aún podría usarse como un 'mejor C'.

Creo que es desafortunado que Ada parezca usarse solo en algunos nichos. En muchos sentidos, es un Pascal ++, pero sin la carga de ser compatible hacia arriba con un lenguaje que ya era un desastre serio para empezar. (editar: el lío serio es, por supuesto, C. Pascal es un lenguaje hermoso pero algo poco práctico).

================================================== ==============

EDITAR: estaba escribiendo una respuesta a una nueva pregunta ("¿En qué casos es necesario C ++ cuando estamos programando microcontroladores"?) Que se cerró refiriéndose a esta, así que agregaré lo que escribí:

Nunca hay una razón absoluta para el uso de cualquier lenguaje de programación, pero puede haber argumentos que tengan más o menos peso en una situación particular. Se pueden encontrar discusiones sobre esto en muchos lugares, con posiciones tomadas que van desde "nunca usar C++ para un microcontrolador" hasta "siempre usar C++". Estoy más con la última posición. Puedo dar algunos argumentos, pero tendrás que decidir por ti mismo cuánto peso tienen en una situación particular (y en qué dirección).

  • Los compiladores de C++ son más raros que los compiladores de C; para algunos objetivos (por ejemplo, PIC de núcleo de 12 y 14 bits) no hay compiladores de C++ en absoluto.
  • Los (buenos) programadores de C++ son más raros que los (buenos) programadores de C, especialmente entre aquellos que también tienen (algo) conocimientos en electrónica.
  • C++ tiene más construcciones que C que no son apropiadas para sistemas pequeños (como excepciones, RTTI, uso frecuente del montón).
  • C++ tiene un conjunto más rico de bibliotecas (estándar) que C, pero una consecuencia del punto anterior es que las bibliotecas de C++ a menudo usan funciones que son inapropiadas para sistemas pequeños y, por lo tanto, no son útiles en sistemas pequeños.
  • C++ tiene más construcciones que C que te permiten pegarte un tiro en el pie.
  • C ++ tiene más construcciones que C que le permiten evitar dispararse en el pie (sí, en mi opinión, esto y el anterior son ciertos).
  • C ++ tiene un conjunto más rico de mecanismos de abstracción, por lo que permite mejores formas de programación, especialmente para bibliotecas.
  • Las características del lenguaje C++ (por ejemplo, constructores/destructores, funciones de conversión) hacen que sea más difícil ver a través del código la máquina generada y, por lo tanto, el costo en espacio y tiempo de una construcción del lenguaje.
  • La construcción del lenguaje C ++ hace que sea menos necesario saber cómo se traducen exactamente a código de máquina porque hacen 'lo correcto' de una manera más abstracta.
  • El estándar del lenguaje C++ está evolucionando rápidamente y los grandes compiladores (gcc, clang, microsoft) lo están adoptando rápidamente. C está evolucionando bastante lento, y la adopción de algunas características más nuevas (arreglos de variantes) es escasa e incluso se ha revertido en un estándar posterior. Este punto en particular es interesante porque diferentes personas lo usan para apoyar las posiciones opuestas.
  • C++ es sin duda una herramienta más afilada que C. ¿Confías en que tus programadores (o en ti mismo) usarán una herramienta de este tipo para hacer una hermosa escultura, o temes que se lastimen y prefieres conformarte con un producto menos hermoso pero de menor riesgo? ? (Recuerdo que mi profesor de escultura me dijo una vez que las herramientas desafiladas pueden, en algunas situaciones, ser más peligrosas que las afiladas).

Mi blog tiene algunos escritos sobre el uso de C++ en sistemas pequeños (= microcontroladores).

Espero agregar más luz que calor a esta discusión sobre C++ en sistemas bare metal y con recursos limitados.

Problemas en C++:

  • Las excepciones son especialmente un problema de RAM, ya que el "búfer de emergencia" requerido (donde va la excepción de falta de memoria, por ejemplo) puede ser más grande que la RAM disponible y ciertamente es un desperdicio para los microcontroladores. Para obtener más información, consulte n4049 y n4234 . Deben estar apagados (que actualmente es un comportamiento no especificado, así que asegúrese de no tirarlos nunca). SG14 está trabajando actualmente en mejores formas de hacer esto.

  • RTTI probablemente nunca valga la pena, debe desactivarse

  • Construcciones de depuración grandes, aunque esto no es un problema en el desarrollo de escritorio clásico, si la depuración no cabe en el chip, puede ser un problema. El problema surge del código con plantilla o de las llamadas a funciones adicionales agregadas para mayor claridad. El optimizador eliminará nuevamente estas llamadas de funciones adicionales y la claridad o flexibilidad añadidas pueden ser una gran ventaja, sin embargo, en las compilaciones de depuración esto puede ser un problema.

  • Asignación de montones. Aunque STL permite el uso de asignadores personalizados, esto puede ser complejo para la mayoría de los programadores. La asignación del almacenamiento dinámico no es determinista (es decir, no es un tiempo real estricto) y la fragmentación puede dar lugar a situaciones inesperadas de falta de memoria a pesar de haber trabajado en las pruebas. La contabilidad que necesita el montón para realizar un seguimiento del espacio libre y el tamaño variable puede ser un problema con los objetos pequeños. Por lo general, es mejor usar la asignación de grupos (tanto en C como en C ++), pero esto puede ser anormal para los programadores de C ++ acostumbrados a usar solo el montón.

  • El polimorfismo en tiempo de ejecución y otras llamadas indirectas suelen ser un gran impacto en el rendimiento, el problema suele ser más porque el optimizador no puede ver a través de ellos más que la búsqueda real y el salto a la dirección. Las llamadas indirectas deben evitarse por este motivo en C y C++, mientras que en C++ están más arraigadas en la cultura (y son bastante útiles en otros dominios).

  • la interfaz implícita con clib puede ser problemática. Puede ser contrario a la intuición que los problemas de clib estén en la categoría de C++, pero el problema surge del intercambio implícito de recursos en entornos concurrentes (el intercambio es más explícito en C). El uso de la implementación común de newLib a menudo arrastra una gran cantidad de información que generalmente no se necesita en uC, por otro lado, newLibNanno no es reentrante, por lo que el acceso debe serializarse (simplificando demasiado aquí). Este es un problema para C también, pero el acceso es más explícito. Como regla general, uno no debería usar nada del espacio de nombres estándar en el contexto de ISR a menos que esté seguro de que no accede al estado en clib de alguna manera (errorno o el montón, por ejemplo). También es importante si está utilizando subprocesos (prefiero RTC) para anular nuevos y eliminar para sincronizar el acceso a malloc y gratis.

En conclusión, C ++ tiene algunos problemas, pero todos ellos son esencialmente reparables o evitables.

Ahora para C, aquí el problema es de orden superior. No tengo la capacidad sintáctica en C para abstraer cosas de una manera que pueda realizar la optimización o verificar invariantes en tiempo de compilación. Por lo tanto, no puedo encapsular correctamente las cosas de manera que el usuario no necesite saber cómo funcionan para poder usarlas y la mayor parte de mi detección de errores se realiza en tiempo de ejecución (que no solo es demasiado tarde sino que también agrega costos). Esencialmente, la única forma de ser genérico en C es a través de datos, paso una cadena de formato a printf o scanf que se evalúa en tiempo de ejecución, por ejemplo. Entonces es bastante difícil para el compilador demostrar que no estoy usando algunas de las opciones que son teóricamente posibles cuando se pasan los datos correctos, lo que significa una posible generación de código muerto y una pérdida del potencial de optimización.

Sé que puedo estar desatando una tormenta de mierda aquí, pero mi experiencia con los microcontroladores de 32 bits es que en una comparación de manzanas con manzanas de C y C ++, ambos escritos por expertos (como en C ++ potencialmente altamente plantillado) C ++ es el lenguaje mucho más eficiente tan pronto como cualquier cosa debe ser genérica (como en cualquier biblioteca) y son esencialmente equivalentes en casos no genéricos. También es más fácil para un novato aprovechar la experiencia de un implementador de bibliotecas experto en C++.

Al mismo tiempo, en realidad hay pocas funciones a las que no puedo pasar datos incorrectos, tan pronto como la entrada no sea un int sino un somethingpara el cual estoy usando un int como método de representación, entonces existe la posibilidad de obtenerlo. incorrecto (pasar un valor inválido o una 'otra Cosa' en lugar de un 'algo'). En C, mi único método para verificar si el usuario se equivocó es en tiempo de ejecución. En C++ tengo la capacidad de realizar algunas comprobaciones, no todas las comprobaciones pero algunas comprobaciones en tiempo de compilación que son gratuitas.

Al final del día, un equipo C suele ser tan poderoso como su programador más débil y el beneficio del código resultante tiene un multijugador de 1 o una penalización de rendimiento. Lo que quiero decir con esto es que es de alto rendimiento para uno y solo un trabajo único en un entorno único de decisiones de diseño únicas o es lo suficientemente genérico como para usarse en múltiples entornos (otro microcontrolador, otra estrategia de administración de memoria, otra latencia vs. compensaciones de rendimiento, etc., etc.) pero tiene un costo de rendimiento inherente.

En C++, los expertos pueden encapsular las cosas y usarlas en muchos entornos donde la generación de código de tiempo de compilación se adapta a la tarea específica y la verificación estática evita que los usuarios hagan cosas estúpidas sin costo alguno. Aquí tenemos mucho menos compromiso entre ser genérico y ser rápido y, por lo tanto, en última instancia, desde el punto de vista de costo versus beneficio, son el lenguaje más eficaz, seguro y productivo.

Es una crítica válida que todavía hay una gran escasez de buenas bibliotecas de C ++ para embebido, esto puede conducir a decisiones pragmáticas para usar principalmente C en un compilador de C ++. Las decisiones de usar solo C en un proyecto son esencialmente ideológicas, por la necesidad de soporte heredado o por admitir que el equipo no es lo suficientemente disciplinado para abstenerse de un conjunto muy selecto de cosas estúpidas que uno puede hacer en C++ pero no en C. y, al mismo tiempo, lo suficientemente disciplinado como para no hacer ninguna de las muchas cosas estúpidas de las que uno no puede protegerse en C pero sí en C++.

Buena adición a mi respuesta :) ¿Quién sería este misterioso amante de C++? Su perfil dice "Aparentemente, estos usuarios prefieren mantener un aire de misterio sobre ellos". (mal inglés, por cierto) PERO AHA, la ubicación es "Bochum, Alemania"... ¡Nos vemos en la conferencia!
Ah, sí, actualicé mi perfil;) es bueno saber que vendrás a emBO ++, será una buena multitud

Mi experiencia: acaba de salir de la escuela de formación con antiguos programadores de Bell Labs; estado trabajando durante 3 años, 2 en proyecto de investigación de pregrado; adquisición de datos / control de procesos en VB.NET. Pasé 1,5 años trabajando en una aplicación de base de datos empresarial en VB6. Actualmente trabajando en proyecto para PC embebido con 2GB de almacenamiento, 512MB de RAM, CPU 500MHz x86; varias aplicaciones que se ejecutan simultáneamente escritas en C++ con un mecanismo IPC en el medio. Sí, soy joven.

Mi opinión: creo que C ++ puede funcionar de manera efectiva dado el entorno que he escrito anteriormente . Es cierto que el rendimiento en tiempo real no es un requisito para la aplicación en la que estoy, y en algunas aplicaciones integradas, eso puede ser un problema. Pero aquí están las cosas que he aprendido:

  • C++ es fundamentalmente diferente de C (es decir, no hay C/C++). Si bien todo lo que es C válido es C++ válido, C++ es un lenguaje muy diferente y uno necesita aprender a programar en C++, no en C, para usarlo de manera efectiva en cualquier situación. En C++, necesita programar orientado a objetos, no procedimentalmente, y no un híbrido de los dos (clases grandes con muchas funciones). En general, debe centrarse en crear clases pequeñas con pocas funciones y componer todas las clases pequeñas juntas en una solución más grande. Uno de mis compañeros de trabajo me explicó que solía programar procedimentalmente en objetos, lo cual es un gran lío y es difícil de mantener. Cuando comencé a aplicar más técnicas orientadas a objetos, descubrí que la mantenibilidad/legibilidad de mi código aumentó.

  • C++ proporciona funciones adicionales en forma de desarrollo orientado a objetos que pueden proporcionar una manera de simplificar el código para que sea más fácil de leer y mantener . Honestamente, no creo que haya mucho en el camino de una mejora en la eficiencia de rendimiento/espacio al hacer OOP. Pero creo que la programación orientada a objetos es una técnica que puede ayudar a dividir un problema complejo en muchas piezas pequeñas. Y eso es útil para las personas que trabajan en el código, un elemento de este proceso que no debe ignorarse.

  • Muchos argumentos en contra de C++ tienen que ver principalmente con la asignación de memoria dinámica. C tiene este mismo problema también. Puede escribir una aplicación orientada a objetos sin usar memoria dinámica, aunque uno de los beneficios de usar objetos es que puede asignar estas cosas dinámicamente de manera sencilla. Al igual que en C, debe tener cuidado con la forma en que administra los datos para reducir las fugas de memoria, pero la técnica RAII lo simplifica en C++ (hace que la memoria dinámica se destruya automáticamente encapsulándola en objetos). En algunas aplicaciones, donde cada ubicación de memoria cuenta, esto puede ser demasiado salvaje y confuso para administrar.

EDITAR:

  • WRT la pregunta "Arduino C ++" : diría que C ++ sin administración dinámica de memoria aún puede ser útil. Puede organizar su código en objetos y luego colocar esos objetos en varias ubicaciones dentro de su aplicación, configurar interfaces de devolución de llamada, etc. Ahora que he estado desarrollando en C++, puedo ver muchas formas en las que una aplicación con todos los datos asignados en el stack aún puede ser útil con objetos. Sin embargo, lo admitiré: en realidad, nunca escribí una aplicación integrada como esa para Arduino, por lo que no tengo pruebas detrás de mi afirmación. Tengo algunas oportunidades para hacer algo de desarrollo de Arduino en un próximo proyecto; espero poder probar mi afirmación allí.
Me gustaría comentar sobre su segundo punto, dice que ayuda a dividir un problema complejo en muchas partes pequeñas y esa característica debe ignorarse. Esta es la razón exacta por la que soy tan pro-C++. Una gran cantidad de investigaciones sobre programación muestra que un crecimiento lineal en el tamaño del programa genera un crecimiento exponencial en el tiempo de desarrollo. esto sigue el camino opuesto, si puede dividir correctamente un programa, entonces puede dar una caída exponencial en el tiempo de desarrollo. Esto es, con mucho, lo más importante.
en su segundo punto también: el simple uso de una metodología de diseño OOP no produce un código más compartimentado. Tener un buen diseño base sí lo es, cómo se expresa ese diseño se deja al desarrollador. OOP no define que separe su código correctamente, proporciona otra opción y, más aún, la apariencia de que lo hizo, pero ciertamente no impone un buen diseño, eso depende del desarrollador.
Eso siempre es cierto. Nunca he oído hablar de un lenguaje que imponga un buen diseño. Creo que principalmente damos a entender que ese es el trabajo de los desarrolladores y que C ++ lo hace fácil de usar e implementar de manera organizada.
@Mark - Estoy de acuerdo. Ha sido un proceso de aprendizaje para mí.
"En C ++, necesita programar orientado a objetos, no procedimentalmente", ¿por qué? puede hacer C ++ procedimental similar a C, y simplemente elegir y elegir entre las funciones de C ++ que desee. por ejemplo, Const, reference, enum calss, namespace, ... Te perderías todos los beneficios de C ++, pero aún estarías mejor que con C simple.

Sí, el problema con C++ es la mayor huella del código.

En algunos sistemas, está contando bytes y, en ese caso, tendrá que aceptar un costo de ejecución que, cerca de los límites de sus sistemas, aumenta el costo de desarrollo de C.

Pero, incluso en C, para un sistema bien diseñado necesita mantener todo encapsulado. Los sistemas bien diseñados son difíciles, y C++ brinda a los programadores un lugar para un método de desarrollo muy estructurado y controlado. Aprender programación orientada a objetos tiene un costo, y si desea cambiar a él, lo acepta y, en muchos casos, la gerencia preferiría continuar con C y no pagar el costo, ya que es difícil medir los resultados de un cambio que aumenta la productividad. Puede ver un artículo del gurú de los sistemas integrados Jack Ganssle aquí .

La gestión de memoria dinámica es el diablo. Realmente no, el diablo es el enrutamiento automático, la gestión dinámica de la memoria funciona muy bien en una PC, pero puede esperar reiniciar una PC al menos cada pocas semanas. Descubrirá que, a medida que un sistema integrado continúa funcionando durante 5 años, la administración dinámica de la memoria realmente puede estropearse y comenzar a fallar. Ganssle analiza cosas como apilar y amontonar en su artículo.

Hay algunas cosas en C++ que son más propensas a causar problemas y usan muchos recursos, la eliminación de la administración de memoria dinámica y las plantillas son grandes pasos para mantener la huella de C++ más cerca de la huella de C. Esto sigue siendo C++, no necesita dinámico gestión de memoria o plantillas para escribir bien en C++. No me di cuenta de que eliminaron las excepciones, considero que las excepciones son una parte importante de mi código que elimino en el lanzamiento, pero uso hasta ese momento. En las pruebas de campo, puedo hacer que las excepciones generen mensajes para informarme sobre la detección de una excepción.

Solía ​​estar de acuerdo en que la huella del código es un problema, pero recientemente parece que el tamaño del flash tiene muy poca influencia en el precio de un microcontrolador, mucho menos que el tamaño de la RAM o la cantidad de pines IO.
El argumento sobre la memoria dinámica es más importante en mi opinión. He visto sistemas industriales que podrían funcionar durante semanas sin parar, pero la capa de diagnóstico (escrita en C++) limitaría el tiempo de reinicio a unas 12 horas.

Pensé que esta perorata anti-C++ de Linus Torvalds era interesante.

Una de las peores características absolutas de C++ es cómo hace que muchas cosas dependan del contexto, lo que significa que cuando observa el código, una vista local rara vez brinda suficiente contexto para saber qué está sucediendo.

No está hablando del mundo de los sistemas integrados, sino del desarrollo del kernel de Linux. Para mí, la relevancia proviene de esto: C ++ requiere comprender un contexto más amplio y puedo aprender a usar un conjunto de plantillas de objetos, no confío en mí mismo para recordarlos cuando tenga que actualizar el código en unos meses.

(Por otro lado, actualmente estoy trabajando en un dispositivo integrado que usa Python (no C ++, pero usa el mismo paradigma OOP) que tendrá exactamente ese problema. En mi defensa, es un sistema integrado lo suficientemente poderoso como para llamarlo PC Hace 10 años.)

Podemos diferir, pero me parece que con solo abrir cualquier proyecto no puedo saber qué está pasando inmediatamente, pero si sé algo sobre lo que está haciendo y tengo algo bien codificado en C y algo bien codificado en C++, el C++ siempre parece más claro. Todavía necesita implementar la encapsulación para un buen desarrollo en C, lo que hace que C ++ sea muy fácil de hacer. El uso adecuado de las clases puede dejar muy claro dónde están sus interfaces, y pueden manejarse completamente a través de un objeto.
Totalmente de acuerdo en encapsulación y clases. Sobrecarga de operadores y herencia, no tanto.
Jaja, sí, la sobrecarga de operadores se puede usar para ofuscar la función del código. Si alguien está sobrecargando al operador, debe ser por razones claras o no hacerlo en absoluto. La herencia solo debe usarse en casos específicos en los que realmente está haciendo algo que es como el padre con algunas adiciones. Creo que no usaría ninguna de las dos funciones en OOP. He usado ambos, pero en un sistema integrado no puedo pensar en un caso en el que lo haría. Del mismo modo que creo que un compilador con un límite de 80 caracteres en los nombres de las variables debería descartarse de inmediato.
Simplemente vomité un poco en mi boca al pensar en programar un MCU en Python...
No eres el único, pero si funciona bien y es eficiente, puedo perdonar.
Tengo una regla general, si puede hacer la tarea mejor y más rápido, entonces lo usaré. en algunos casos uno es más importante que el otro.
Mi afirmación es que el tiempo del programador suele ser más caro que el hardware. Imagínese intentar hacer programación de red en C vs. Python, para ahorrar $50 en hardware. Para aplicaciones de pequeño volumen, los lenguajes de alto nivel ganan, ahora que el hardware integrado es tan poderoso como es.
Estoy de acuerdo, trabajo en una empresa en la que esperamos vender muchos millones de dispositivos, por lo que los gastos no recurrentes son bastante bajos por unidad, pero el hardware es importante. En un proyecto pequeño tiene sentido. Quise decir con mi comentario anterior que mejor y más rápido son importantes. Sin embargo, solo necesitas más rápido.
@pingswept Estoy de acuerdo, el tiempo del programador es caro. Como señala Linus, en el caso de los voluntarios de código abierto, no tiene precio. Sin embargo, comercialmente, el costo de desarrollo frente a la fabricación tiene un gran impacto una vez que entra en volumen. Mi función actual es migrar un sistema integrado linux+python+zigbee a arm-cortex-m3 para ahorrar costos.
Suena como un proyecto impresionante Joby.
@Kortuk "la sobrecarga del operador se puede usar para ofuscar la función del código". No sé por qué todo el mundo usa esto como argumento contra la sobrecarga de operadores. Podría decir "Los nombres de las funciones se pueden usar para ofuscar la función del código". Podría tener una función llamada OpenFile() que en realidad elimina el archivo.
@Rocketmagnet, estuvo de acuerdo, la parte importante es diseñar su código para seguir métodos claros y concisos y solo sobrecargar un operador si la sobrecarga tiene sentido, como permitir que un + sobrecargado haga una suma de matriz en su clase de matriz.
Python es un lenguaje hermoso pero más diseñado para sistemas operativos. Pero no tendría ningún problema en probarlo para MCU si alguien tuviera la plataforma adecuada... Python se amplía con bastante frecuencia con bibliotecas C por lo que he visto. Programo mi raspberry pi en Python, ¿es un sistema 'incrustado'?

Creo que otras respuestas defendieron bastante bien los pros y los contras y los factores de decisión, por lo que me gustaría resumir y agregar algunos comentarios.

Para microcontroladores pequeños (8 bits), de ninguna manera. Solo estás pidiendo hacerte daño, no hay ganancia y renunciarás a demasiados recursos.

Para los microcontroladores de gama alta (por ejemplo, 32 bits, 10 o 100 MB para RAM y almacenamiento) que tienen un sistema operativo decente, está perfectamente bien y, me atrevería a decir, incluso recomendado.

Entonces la pregunta es: ¿dónde está el límite?

No estoy seguro, pero una vez desarrollé un sistema para un uC de 16 bits con 1 MB de RAM y 1 MB de almacenamiento en C++, solo para arrepentirme más tarde. Sí, funcionó, pero el trabajo extra que tuve no valió la pena. Tenía que hacer que encajara, asegurarme de que cosas como las excepciones no produjeran fugas (el soporte de OS+RTL tenía bastantes errores y era poco fiable). Además, una aplicación orientada a objetos normalmente hace muchas asignaciones pequeñas, y la sobrecarga del montón para ellas fue otra pesadilla.

Dada esa experiencia, supongo que para proyectos futuros elegiré C++ solo en sistemas de al menos 16 bits y con al menos 16 MB para RAM y almacenamiento. Ese es un límite arbitrario, y probablemente variará según cosas como el tipo de aplicación, estilos de codificación y modismos, etc. Pero dadas las advertencias, recomendaría un enfoque similar.

Tengo que discrepar aquí, no hay un punto repentino en el que C ++ se vuelva aceptable debido a los recursos del sistema, las buenas prácticas de diseño pueden mantener la huella de C ++ donde está la huella de C. Esto da como resultado un código con diseños OOP que ocupan el mismo espacio. Una C mal escrita puede ser igual de mala.
Bueno, depende de qué tan grande sea su aplicación y cuánto use ciertas funciones que requieren más espacio (como plantillas y excepciones). Pero personalmente prefiero usar C que tener que limitarme a un C++ restringido. Pero incluso entonces tendrá la sobrecarga de un RTL más grande, procesadores de método virtual, invocación de cadena de constructor/destructor... estos efectos pueden mitigarse con una codificación cuidadosa, pero entonces está perdiendo la razón principal para el uso de C++, la abstracción y perspectiva de alto nivel.
"Pero incluso entonces tendrás la sobrecarga de un RTL más grande" - tonterías, cuando uso C++ obtengo el mismo RTL que para C: esencialmente 0.
"thunks de método virtual": no tengo idea de qué son, pero ciertamente no los obtiene a menos que use funciones virtuales , en cuyo caso su programa C equivalente habría tenido punteros de función.
"Prefiero usar C que tener que limitarme a un C++ restringido": no puedo hablar por usted, pero cuando hago C en un microcontrolador pequeño, uso un C reentrenado, por ejemplo: sin montón, sin flotadores , sin setjmp/jongjmp. Asimismo, utilicé un C++ restringido.

Hay algunas características de C++ que son útiles en los sistemas integrados. Hay otros, como las excepciones, que pueden ser costosos y cuyos costos pueden no ser siempre evidentes.

Si tuviera mis preferencias, habría un lenguaje popular que combinaría lo mejor de ambos mundos e incluiría algunas características que faltan en ambos lenguajes; algunos proveedores incluyen algunas de estas características, pero no hay estándares. Algunas cosas que me gustaría ver:

  1. Manejo de excepciones un poco más como Java, donde las funciones que pueden lanzar o filtrar excepciones deben declararse como tales. Si bien un requisito para tales declaraciones puede ser algo molesto desde una perspectiva de programación, mejoraría la claridad del código en los casos en que una función puede devolver un número entero arbitrario si tiene éxito, pero también puede fallar. Muchas plataformas podrían manejar esto de forma económica en el código, por ejemplo, teniendo el valor de retorno en un registro y una indicación de éxito/fracaso en la bandera de acarreo.
  2. Sobrecarga de funciones estáticas y en línea únicamente; Según tengo entendido, los organismos de estándares para C han evitado la sobrecarga de funciones para evitar la necesidad de modificar el nombre. Permitir sobrecargas de funciones estáticas y en línea solo evitaría ese problema y daría el 99,9% del beneficio de sobrecargar funciones externas (ya que los archivos .h podrían definir sobrecargas en línea en términos de funciones externas con nombres diferentes)
  3. Sobrecargas para valores de parámetros constantes arbitrarios o específicos que se pueden resolver en tiempo de compilación. Algunas funciones pueden estar en línea muy eficientemente cuando se pasan con cualquier valor constante, pero en línea muy mal si se pasa una variable. Otras veces, el código que puede ser una optimización si un valor es constante puede ser una pesimización si no lo es. Por ejemplo:
    copia vacía en línea_uint32s(uint32_t *dest, const uint32_t *src, __is_const int n)
    {
      si (n <= 0) regresa;
      si no (n == 1) {destino[0] = src[0];}
      si no (n == 2) {dest[0] = src[0]; destino[1] = origen[1];}
      si no (n == 3) {dest[0] = src[0]; destino[1] = origen[1]; destino[2] = origen[2];}
      si no (n == 4) {dest[0] = src[0]; destino[1] = origen[1]; destino[2] = origen[2]; destino[3] = origen[3];}
      else memcpy((void*)dest, (const void*)src, n*sizeof(*src));
    }
    
    Si 'n' puede evaluarse en tiempo de compilación, el código anterior será más eficiente que una llamada a memcpy, pero si 'n' no puede evaluarse en tiempo de compilación, el código generado sería mucho más grande y más lento que el código que simplemente llamado memcpy.

Sé que el padre de C++ no está muy interesado en una versión integrada de C++, pero creo que podría ofrecer algunas mejoras considerables con respecto al uso de C.

¿Alguien sabe si se está considerando algo como lo anterior para algún tipo de estándar?

@Joby Taffey: Supongo que edité mi publicación para omitir mencionar que el creador de C++ no estaba interesado en un subconjunto incrustado; Soy consciente de que hubo esfuerzos, pero según tengo entendido, en realidad no habían llegado tan lejos. Creo que habría un uso definitivo para un lenguaje estandarizado que sería compatible con procesadores de 8 bits, y características como las que describí anteriormente parecerían útiles en cualquier plataforma. ¿Has oído hablar de algún idioma que ofrezca cosas como el n.° 3 anterior? Parecería muy útil, pero nunca he visto que ningún idioma lo ofrezca.
"El padre de C++" no tiene experiencia en programación de sistemas integrados, entonces, ¿por qué le importaría a alguien su opinión?
@Lundin: El hecho de que algunas personas influyentes parezcan preocuparse por sus opiniones sobre varios asuntos parece ser una razón, en sí misma, para que otras personas lo hagan. Estoy pensando que desde que escribí lo anterior, el poder cada vez mayor de las plantillas puede haber agregado nuevas posibilidades para tener sobrecargas basadas en las constantes que se pueden resolver en tiempo de compilación, aunque mucho menos limpiamente que si tal cosa fuera compatible como compilación. función de tiempo (por lo que entiendo, uno especificaría una plantilla que debería probar varias cosas en orden e ir con la primera que no falla ...
... pero eso requeriría que el compilador desperdicie un poco de esfuerzo compilando sustituciones potenciales que luego terminarían siendo descartadas. Ser capaz de decir más claramente "Si esto es una constante, haz esto; de lo contrario, haz esto" sin ningún "comienzo en falso" parecería un enfoque más limpio.
Sí, bueno, la razón principal por la que EC ++ recibió una buena recepción parece ser debido a este difuso "padre en las nubes" que probablemente nunca haya visto un microcontrolador. Hice un proyecto de microcontrolador en EC++ hace 10 años y tenía mucho sentido para mí en ese entonces. Pero esa también fue la última vez que usé C++ en un sistema integrado, así que estoy bastante desactualizado :) Hoy en día, MISRA C++ suena como una alternativa interesante si se necesita un subconjunto restringido del lenguaje.
@Lundin: no estoy familiarizado con MISRA C++. Creo que MISRA C probablemente debería separarse de "otro" C y especificar que, por ejemplo, un compilador MISRA C, dado uint16_t x;que la declaración x=(uint16_t)(x*x);debe producir un resultado mod-65536 independientemente del valor xo el tamaño de int. Aunque el estándar nunca ha impuesto ningún requisito cuando el tamaño intes de 17 a 32 bits y xes de 46341 o superior, los compiladores de 32 bits solían comportarse igual que los compiladores de 16 bits en tales casos, pero hoy en día pueden comportarse de formas extrañas y extrañas.
@Lundin: Si bien supongo que uno podría argumentar que escribir el código como x=(uint16_t)(1u*x*x);sería mejor, ya que incluso un compilador hipermoderno no podrá estropearlo, no veo forma en que una especificación de lenguaje que solo requiera que los compiladores se comporte de manera consistente dado que la última redacción debe considerarse "mejor" que una que exigía que la anterior redacción debe producir los mismos resultados cuando intes de 17 a 32 bits como lo haría para tamaños más grandes o más intpequeños.

C++ es más que un lenguaje de programación:

a) Es un "mejor" C b) Es un lenguaje orientado a objetos c) Es un lenguaje que nos permite escribir programas genéricos

Aunque todas estas funciones se pueden usar por separado, los mejores resultados se logran cuando se usan las tres al mismo tiempo. No obstante, si elige elegir solo uno de ellos, la calidad del software integrado aumentará.

a) Es una "mejor" C

C++ es un lenguaje fuertemente tipado; más fuerte que C. Sus programas se beneficiarán de esta función.

Algunas personas tienen miedo de los punteros. C++ incluye las referencias. Funciones sobrecargadas.

Y vale la pena decir: ninguna de estas características incurrieron en programas más grandes o más lentos.

b) Es un lenguaje orientado a objetos.

Alguien dijo en esta publicación que abstraer la máquina en microcontroladores no es una buena idea. ¡Equivocado! Todos nosotros, los ingenieros embebidos, siempre hemos abstraído la máquina, solo que con otra sintaxis que la de C++. El problema que veo con este argumento es que algunos programadores no están acostumbrados a pensar en objetos, por lo que no ven los beneficios de la programación orientada a objetos.

Siempre que esté listo para usar el periférico de un microcontrolador, es probable que el periférico haya sido abstraído para nosotros (usted o un tercero) en forma de controlador de dispositivo. Como dije antes, ese controlador usa la sintaxis de C, como muestra el siguiente ejemplo (tomado directamente de un ejemplo de NXP LPC1114):

/* Configuración del temporizador para coincidencia e interrupción en TICKRATE_HZ */

Chip_TIMER_Reset(LPC_TIMER32_0);

Chip_TIMER_MatchEnableInt(LPC_TIMER32_0, 1);

Chip_TIMER_SetMatch(LPC_TIMER32_0, 1, (timerFreq / TICKRATE_HZ2));

Chip_TIMER_ResetOnMatchEnable(LPC_TIMER32_0, 1);

Chip_TIMER_Enable(LPC_TIMER32_0);

¿Ves la abstracción? Entonces, cuando se usa C++ para el mismo propósito, la abstracción se lleva al siguiente nivel a través del mecanismo de abstracción y encapsulación de C++, ¡sin costo alguno!

c) Es un lenguaje que nos permite escribir programas genéricos

Los programas genéricos se logran a través de plantillas, y las plantillas tampoco tienen costos para nuestros programas.

Además, el polimorfismo estático se logra con plantillas.

Métodos virtuales, RTTI y excepciones.

Hay un compromiso cuando se utilizan métodos virtuales: mejor software frente a alguna penalización en el rendimiento. Sin embargo, recuerde que es probable que el enlace dinámico se implemente mediante una tabla virtual (una matriz de punteros de función). He hecho lo mismo en C muchas veces (incluso de forma regular), por lo que no veo inconvenientes en el uso de métodos virtuales. Además, los métodos virtuales en C++ son más elegantes.

Finalmente, un consejo sobre RTTI y excepciones: NO LOS USE en sistemas integrados. Evítalos a toda costa!!

Mi fondo, incrustado (mcu, pc, unix, otros), en tiempo real. Seguridad crítica. Presenté a un empleador anterior a STL. Ya no hago eso.

Algo de contenido de Flame

¿C++ es adecuado para sistemas embebidos?

Meh. C++ es un dolor de escribir y un dolor de mantener. C+ está más o menos bien (no use algunas funciones)

C++ en Microcontroladores? ¿RTOS? ¿Tostadoras? PC integradas?

Nuevamente digo Meh. C+ no es tan malo, pero ADA es menos doloroso (y eso es realmente decir algo). Si tienes suerte como yo, puedes hacer Java incrustado. El acceso a la matriz verificada y la aritmética sin punteros hacen que el código sea muy confiable. Los recolectores de basura en Java incorporado no son la prioridad más alta, y hay memoria de alcance y reutilización de objetos, por lo que el código bien diseñado puede ejecutarse para siempre sin un GC.

¿Es OOP útil en microcontroladores?

Seguro es. El UART es un objeto... El DMAC es un objeto...

Las máquinas de estado de objetos son muy fáciles.

¿C++ aleja demasiado al programador del hardware para ser eficiente?

A menos que sea un PDP-11, C no es tu CPU. C++ era originalmente un preprocesador encima de C, por lo que dejaría de burlarse de Bjarne Stroustrup por tener simulaciones lentas de Simula mientras estaba en AT&T. C++ no es tu CPU.

Obtenga una MCU que ejecute códigos de bytes de Java. Programa en Java. Ríete de los chicos C.

¿Debería considerarse el C++ de Arduino (sin administración de memoria dinámica, plantillas, excepciones) como "C++ real"?

No. al igual que todos los compiladores de C bastardos para MCU.

En cuarto lugar, Embedded Java o Embedded ADA están estandarizados (más o menos); todo lo demás es tristeza.

¿Es tan fácil encontrar microcontroladores compatibles con Java? Creo que esto limitaría considerablemente las opciones. ¿Y cuáles son sus experiencias sobre la penalización de rendimiento (dado que en uCs normalmente no tendría JIT)? ¿Qué pasa con el impacto de la imprevisibilidad de GC en los sistemas en tiempo real?
¿Qué MCU existen que admitan Java integrado?
www.ajile.com para empezar.
+1 para Ada. Tiene mucho que ofrecer integrado, incluido Arduinos.
Java VM portátil para micros escrito en c es de código abierto. dmitry.co/index.php?p=./04.Pensamientos/…

<despotricar>

Creo que C ++ es un lenguaje de mierda en primer lugar. Si quiere usar OOP, escriba programas Java. C ++ no hace nada para hacer cumplir los paradigmas OOP, ya que el acceso directo a la memoria está completamente dentro de su poder para (ab) usar.

Si tiene una MCU, lo más probable es que esté hablando de menos de 100 kB de memoria flash. Quieres estar programando en un lenguaje cuya abstracción de memoria es: cuando declaro una variable o una matriz, obtiene memoria, punto; malloc (también conocido como palabra clave "nueva" en C++) debería estar más o menos prohibido para su uso en software integrado, excepto quizás en raras ocasiones una llamada durante el inicio del programa.

Demonios, hay (con frecuencia) momentos en la programación integrada en los que C no es lo suficientemente bajo y necesita hacer cosas como asignar variables a registros y escribir ensamblaje en línea para reforzar sus rutinas de servicio de interrupción (ISR). Las palabras clave como "volátil" se vuelven bastante importantes de entender. Pasas mucho tiempo manipulando la memoria a nivel de bit , no a nivel de objeto .

¿Por qué querrías engañarte pensando que las cosas son más simples de lo que en realidad son?

</rant>

Mi problema aquí es simplemente, ¿por qué quiero saber la complejidad del controlador que se escribió para controlar USART1 si se ha desarrollado completamente para manejar la interfaz?
No lo voté en contra, pero me gustaría señalar que C ++ no necesita hacer cumplir la programación orientada a objetos, solo brinda las herramientas para hacerlo. Hacer cumplir buenos estándares de codificación es el trabajo del desarrollador. Puede ayudar si el idioma lo hace más fácil, pero el idioma nunca lo hará por sí solo. C puede ser ilegible en algunos casos.
Todos los idiomas sirven para algo. C++ es rápido. OOP, si está bien hecho, hace que sea mucho más fácil para múltiples desarrolladores trabajar en paralelo y codificar para lo desconocido. Creo que es por eso que tiene tanta tracción en el desarrollo de juegos.
Sí estoy de acuerdo. La razón por la que lo veo para el mundo integrado es por la gran cantidad de características y funciones que se agregan a muchos de los diferentes sistemas que ya existen y los nuevos sistemas que se están desarrollando. El proyecto se hace cada vez más grande. O nos tomamos más tiempo para desarrollarlos o comenzamos a aplicar y retorcer lo que el mundo de CS ya ha hecho en las PC.
Estoy de acuerdo con vicatsu. ¿Por qué es rechazado? Soy un profesional del software con más de 20 años de experiencia (no integrado). Y mi opinión sobre C++ es que es el lenguaje más caro, desafortunadamente popular debido a la temprana popularidad del C simple. El C simple era popular solo por una razón: había un solo libro realmente bueno sobre este lenguaje que estaba muy bien escrito (la del lenguaje C y C++ es completamente opuesto)
@Rocketmagnet Esta pregunta pedía una respuesta como la mía :-p. Es solo una opinión, y puedo estar de acuerdo en estar en desacuerdo con los demás. Diablos, hago mucha programación Arduino y todo eso está basado en C ++. No significa que tenga que gustarme.
Incluso iría un paso más allá. Si su "sistema integrado" es de 8 bits, con mucha memoria/recursos limitados, sin sistema operativo, entonces cualquier cosa más allá del buen viejo C solo está agregando sobrecarga. Por otro lado, si es, digamos, un BeagleBoard con Linux, muchos recursos, sin requisitos de casi RT, entonces use Mono y C#. La productividad y la mantenibilidad serán órdenes de magnitud mayores. C++ simplemente le brinda todos los dolores de cabeza de C sin la simplicidad y la baja sobrecarga.
malloc (aka "new" keyword in C++) should be more or less banned from use in embedded software--> La dulzura adicional (con intención de sarcasmo) es que newtambién puede arrojar excepciones. Ahora buena suerte con eso.

Los sistemas integrados están diseñados para realizar una tarea específica, en lugar de ser una computadora de propósito general para múltiples tareas. Un sistema embebido es una combinación de hardware y software de computadora. C es la madre de todas las lenguas modernas. Es un lenguaje de bajo nivel pero potente y maneja todo tipo de hardware. Por lo tanto, C/C++ es una opción óptima para desarrollar software para sistemas integrados, que es muy útil para todos los sistemas integrados. Como sabemos, C es un lenguaje de desarrollo. El sistema operativo UNIX está escrito en C. Debido a que el desarrollo de software exitoso consiste con tanta frecuencia en seleccionar el mejor lenguaje para un proyecto determinado, es sorprendente descubrir que el lenguaje C/C++ ha demostrado ser apropiado para procesadores de 8 y 64 bits. ; en sistemas con bytes, kilobytes y megabytes de memoria. C tiene el beneficio de la independencia del procesador, lo que permite a los programadores concentrarse en algoritmos y aplicaciones, en lugar de los detalles de la arquitectura del procesador en particular. Sin embargo, muchas de estas ventajas se aplican igualmente a otros lenguajes de alto nivel. ¿Pero C/C++ tuvo éxito donde tantos otros lenguajes han fallado en gran medida?

Realmente no estoy seguro de lo que esto agrega a la discusión.