¿C ++ es adecuado para sistemas integrados?

168

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

Microcontroladores? RTOSes? Tostadoras? PC integradas?

¿OOP es útil en microcontroladores?

¿C ++ elimina el programador demasiado lejos del hardware para ser eficiente?

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

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

Toby Jaffey
fuente
55
Pregunta rápida: cuando dices incrustado , ¿te refieres a microcontrolador? ¿microprocesador? x86 embebido / PC embebido?
J. Polfer
1
No tenía la intención de provocar una guerra santa; la intención era aprender cuáles eran tus argumentos en contra de eso.
J. Polfer
2
Ha aparecido en varias preguntas antes, así que pensé que un lugar central sería bueno.
Toby Jaffey
44
C ++ vs incrustado es un tema polémico. Tengo una opinión sólida, pero no pensé que fuera justo hacer una pregunta y jugar en los puntos de puntuación. Espero que un wiki comunitario haga una discusión más equilibrada.
Toby Jaffey
13
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 están ejecutando un sistema operativo, tienen memoria limitada, pueden no ser von-Neuman, pueden tener varias restricciones de hardware en las pilas de llamadas, pilas de datos, no se puede 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".
Olin Lathrop

Respuestas:

135

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 de usar C ++ incluso cuando lo reduce a algo como "C +" incluso en un micro mundo de 8 bits. ¿Qué quiero decir con "C +"? Quiero decir, no use new / delete, evite excepciones, evite las clases virtuales con herencia, posiblemente evite la herencia por completo, tenga mucho cuidado con las plantillas, use funciones en línea en lugar de macros y use constvariables en lugar de #defines.

He trabajado tanto en C como en C ++ en sistemas embebidos durante más de una década, y parte de mi entusiasmo juvenil por C ++ definitivamente ha desaparecido debido a algunos problemas del mundo real que sacuden la ingenuidad de uno. He visto lo peor de C ++ en un sistema embebido al que me gustaría referirme como "programadores de CS enloquecidos en un mundo de 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 poderosa, muy parecida a una espada de dos filos que puede cortar tanto el brazo como la pierna si no se educa y se disciplina adecuadamente en su lenguaje y 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 de abstracción muy altos y crear interfaces ofuscadas que pierdan su significado a largo plazo, y eso se debe en parte a la flexibilidad de C ++ para resolver el mismo problema con muchas características de lenguaje diferentes (plantillas, OOP, procedimientos, RTTI, OOP + plantillas, sobrecarga, en línea).

Terminé dos seminarios de 4 horas sobre software embebido en C ++ por el gurú de C ++, Scott Meyers. Señaló algunas cosas sobre plantillas que nunca antes había considerado y cuánto más pueden ayudar a crear un código crítico para la seguridad. Lo esencial es que no puede tener un código muerto en el software que tiene que cumplir con los estrictos requisitos de código crítico 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 aprender más sobre su uso para diseñar correctamente esta característica, 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 juicioso de la alineación, y debo decir que todavía soy escéptico sobre ser entusiasta de las plantillas. Tiendo a alejarme de ellos, a pesar de que él dice que solo deben aplicarse donde se convierten en la mejor herramienta. También señala que C ++ le brinda las herramientas para crear interfaces realmente buenas que sean fáciles de usar correctamente y dificulten el uso incorrecto. De nuevo, esa es la parte difícil. Uno debe llegar a un nivel de dominio en C ++ antes de que pueda saber cómo aplicar estas características de la manera más eficiente para ser la mejor solución de diseño.

Lo mismo vale para OOP. En el mundo incrustado, debe familiarizarse con el tipo de código que el compilador va a escupir para saber si puede manejar los costos en 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 la fecha límite. ¿Esa nueva clase de 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 de 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) .

Lo digo todo para decir que C ++ tiene su lugar en el mundo incrustado. 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 de nuevo, debe Edúcate y no tengas miedo de aprender cómo hacerlo.

Jay Atkinson
fuente
1
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 constantemente de pequeñas maneras, pero un error en C ++ será más raro, pero cuando lo arruinas perderás una pierna. Gracias por escribir una respuesta clara con algo de experiencia que no tengo.
Kortuk
3
En la nota de las especialidades en informática que se vuelven locas en EE. UU. En mi trabajo, el peor fragmento de código que tenemos fue escrito por un experto en CS. Pasamos una eternidad intentando enseñarle cuál era el hardware. Hizo un sistema estructurado usando UML y construyó todo el sistema basado en él en Java usando la herencia adecuada y así sucesivamente. 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 cuán completamente se ofuscó todo con la herencia.
Kortuk
2
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 funciona a la perfección, pero después de 2 o 3 años, la entropía se activa si no se realiza un esfuerzo serio en la refactorización a medida que te desarrollas. Eso es lo que estoy enfrentando en este momento ... el código se pudre más rápido con el tiempo en C ++.
Jay Atkinson
2
UML y máquinas de estado. Realmente necesitas 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 algún tiempo asimilarlo.
Jay Atkinson
2
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 RAM? Entonces podría ser mejor evitar volverse loco en 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 pegas el mundo "virtual" en esa clase, obtienes un puntero adicional, que podría ser de 8 bits, 16 bits o 32 bits dependiendo del sistema, por cada instancia que declares de ese objeto. Ni siquiera te darás cuenta, y hombre,
Jay Atkinson
56

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 traída 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 OK:

  • funciones virtuales: solía estar en contra de esto, pero el costo de los recursos 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. Utilicé esto recientemente para tener una matriz de objetos que representan cada uno 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 dinámica de memoria: otros lo han mencionado, pero otra razón importante para no utilizar la asignación dinámica de memoria es que representa incertidumbre en el tiempo; Muchas de las razones para utilizar 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 grande
  • excepciones: un no definitivo , debido al golpe de velocidad de ejecución
Jason S
fuente
Gracias por el aporte. Interesante y muy similar a lo que he leído.
Kortuk
1
En realidad, la asignación dinámica de memoria está bien y, a veces, es inevitable. El problema es la asignación dinámica de memoria (y la posterior reutilización). RTTI es un cerdo de memoria, estoy de acuerdo con eso. Pero, ¿cuál es el problema con las excepciones?
Wouter van Ooijen
1
@WoutervanOoijen: El problema con las excepciones es que si foollama bardentro de un bloque try/ catchy barcrea algunos objetos y llamadas boz, lo que arroja una excepción, el sistema tiene que llamar de alguna manera a los destructores de los objetos barcreados antes de devolver el control foo. A menos que las excepciones estén completamente deshabilitadas, barno habrá forma de saber si bozpodría lanzar alguna, y por lo tanto debe incluir un 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 excepciones a escapar ...
supercat
1
... tenía que declararse como tal, entonces solo sería necesario que el compilador incluyera código de manejo de excepciones en los llamadores de tales rutinas. Sin duda, tener que agregar todas las declaraciones requeridas, mientras se espera evitar las innecesarias, sería algo oneroso, pero permitiría que se usen excepciones en lugares donde son útiles, sin agregar gastos generales donde no lo son.
supercat
3
@WoutervanOoijen: Incidentalmente, si estuviera diseñando el ABI para tal manejo de excepciones en el ARM, especificaría que el código que llama a una rutina que puede salir por excepción debería tener R14 apuntando a una dirección dos bytes antes de la dirección de retorno deseada (esto sería ocurrirá 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 de en add r15,r14,#2lugar de mov r15,r14; para salir a través de excepción, ldrhs r0,[r14] / add r15,r14,r0. Costo de ciclo cero para la salida normal, y sin restricciones de marco de pila.
supercat
36

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

En un micro integrado, 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, por lo que son muy ineficientes cuando se usa la pila. Esto significa que debe tener cuidado al pasar variables a funciones, usar matrices y punteros, y la recursividad. Una línea simple 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 usa un lenguaje de alto nivel y le preocupan las limitaciones de tiempo y espacio, debe saber cómo cada característica de ese idioma se traduce en instrucciones de máquina en su MCU (al menos, cada característica que usa). Esto es cierto para C, C ++, Ada, lo que sea. Probablemente todos los idiomas contendrán características que no se traducen de manera eficiente en MCU pequeños. Siempre revise los listados de desensamblaje para asegurarse de que el compilador no esté generando montones de instrucciones para algo trivial.

¿Es C adecuado para MCU integradas? Sí, siempre y cuando vigiles el código generado.
¿C ++ es adecuado para MCU integradas? 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 ++ proporciona un soporte mejorado para:

  • Ocultar datos
  • Mecanografía / verificación más fuerte
  • Transparencia multiperiférica usando clases
  • Plantillas (como siempre si se usa con cuidado)
  • Listas de inicialización
  • const

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

A medida que avanza hasta MCU de 16 o 32 bits, 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 ante la idea de C ++ en un PIC16. Si conoce su idioma y su MCU correctamente, sabrá cómo utilizarlos de manera eficaz.

Rocketmagnet
fuente
3
Esta es una respuesta muy bien expresada y razonable a la pregunta. +1 Saludos!
vicatcu
1
" 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á utilizando una CPU de aficionado de garaje de los años 80.
Lundin
@Lundin - Suspiro. No, significa que está usando una MCU pequeña y barata que está diseñada para ser lo más pequeña y barata posible, no para tener cosas complejas como la indexación de pila.
Rocketmagnet
2
@Rocketmagnet Ok, tal vez en la década de 1990? Hoy en día, los amargos 8 bitters tienen el mismo precio que los 32 bitters. El único motivo que queda para elegir el primero es el consumo actual. Y con respecto a esos 8 bits amargos extraños sin pila: si escribe C en lugar de ensamblador para un MCU tan limitado, es probable que lo esté haciendo mal. Las 4 páginas generadas son, entonces, culpa suya al escribir programas demasiado complejos para la CPU, y esencialmente C es la herramienta incorrecta para la tarea. (He hecho esto en el pasado en Freescale RS08, fue una idea muy estúpida).
Lundin
El procesador @Lundin de 32 bits no es necesario más rápido que el de 16 bits. Esto fue evidente en el día cuando la transición del programa de 16 a 32 bits estaba ocurriendo en el mundo de las PC.
Barleyman
24

Siempre encuentro estos debates entretenidos de leer. No tanto para la discusión intelectual sobre los pros y los contras de los diversos idiomas disponibles, sino porque generalmente puede vincular 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" en los que los expertos en CS y los programadores de mantenimiento 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 de este último grupo para ser justo).

Al final del día, puede desarrollar un excelente software en C o C ++ o insertar un lenguaje aquí . Todo se reduce a las capacidades del desarrollador, no al lenguaje. Ser un experto en un idioma generalmente solo se requiere si ha elegido el idioma equivocado para comenzar y ahora necesita deformarlo 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 las personas comenzar estos argumentos como "Soy un experto en el lenguaje X y bla, bla". Honestamente, desacredito de inmediato a estas personas porque, en mi opinión, ya han abordado el problema desde el ángulo equivocado y todo después de eso está contaminado. por su deseo de usar su herramienta para resolver el problema y mostrar cuán "genial" es.

A menudo veo a los desarrolladores elegir un conjunto de herramientas primero e intentar adaptarlo a su problema en segundo lugar, lo cual es completamente incorrecto y da como resultado soluciones basura.

Como mencioné en un comentario a otra respuesta, estas guerras lingüísticas a menudo se convierten en argumentar que el lenguaje X permite al programador hacer cosas más tontas. Si bien es entretenido leer, todas estas afirmaciones realmente significan que tiene un problema para contratar buenos desarrolladores y necesita abordar ese problema directamente en lugar de tratar de ayudar a la situación al continuar contratando malos desarrolladores y eligiendo herramientas para que puedan hacer tan poco Daño como sea posible.

En mi opinión, buenos desarrolladores, ya sea desarrollo de software o hardware, investigan el problema, diseñan una solución y encuentran las herramientas que les permitan 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-4 idiomas / herramientas de desarrollo para proyectos que eligen 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. Es necesario considerar una multitud de problemas: rendimiento, facilidad de expresión, densidad de código, etc., según el problema en cuestión. No incluí la capacidad de mantenimiento en esa lista por una razón, no me importa el idioma que 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, esto da como resultado un feo desastre para que funcione.

Afirmar que cualquier idioma es "mejor" que cualquier otro es una tontería sin definir un problema particular de interés. 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 sobre muchas características del lenguaje que las personas parecen disfrutar insistiendo.

Si pasa más del 20% de su tiempo en un problema al escribir código, probablemente esté produciendo un sistema muy pobre o tenga desarrolladores muy pobres (o todavía está aprendiendo). Debería pasar la mayor parte de su tiempo haciendo un diagrama inicial del problema y determinando cómo interactúan varias partes de la aplicación. Pegar a un grupo de desarrolladores talentosos en una habitación con un marcador y un problema que resolver y decirles que no se les permite escribir ningún código o elegir ninguna herramienta hasta que se sientan cómodos con todo el sistema hará más para mejorar la calidad del desarrollo de salida y velocidad que elegir cualquier nueva herramienta caliente 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 al 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 desarrollo del "pensamiento" o se ven obligados a usar una herramienta establecida por algún problema político dentro de la empresa, "El hermano de mi jefe trabaja para IBM, por lo que solo podemos usar sus herramientas", ese tipo de basura . O, lo que es peor, obtiene un conjunto de requisitos en constante cambio por parte de la empresa porque no son capaces de realizar una investigación de mercado adecuada o no entienden el impacto de los cambios en el ciclo de desarrollo.

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

Mark
fuente
2
Ahora, no estoy eliminando las pruebas unitarias a nivel de aplicación (por encima del controlador) en ciertos sistemas integrados. Hay algo de 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 loco. 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 hacer una investigación inicial sobre los requisitos, porque se supone que ayuda con el cambio constante de requisitos.
Jay Atkinson
2
Y para poner una nota final en mi comentario súper largo ... No necesitamos expertos en idiomas para trabajar en el diseño. Necesitamos diseñadores expertos que puedan trabajar los idiomas.
Jay Atkinson
1
PRD = documento de requisitos del producto, MRD = documento de requisitos de marketing, TRD = documento de requisitos técnicos. TDD = Test Driven Development.
Jay Atkinson
1
@ Mark: estoy de acuerdo con tus sentimientos de diseño inicial, pero solo hasta cierto punto. Creo que los trabajos pesados ​​de diseño inicial dan sus frutos si a) sus requisitos son bastante estables / conocidos, yb) los desarrolladores que realizan el diseño tienen experiencia . En un anterior. trabajo, me encargaron hacer un diseño y el líder de mi equipo me impidió mucho tiempo, y pensé: "¡Qué cosa más tonta hacer! Diseñar por adelantado ahorra dinero (cf. Código Libro completo) ??" Pero en la codificación descubrí toneladas de cosas que no sabía buscar. Si hubiera hecho mucho diseño y minimizase el tiempo de código, habría sido un desperdicio. JME
J. Polfer
1
@sheepsimulator Obviamente estoy de acuerdo con el segundo punto, supongo que los arquitectos líderes del sistema son desarrolladores experimentados. Sobre el primer punto, en realidad no estoy de acuerdo. Creo que cuanto más espere 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 inexpertos en el personal. Todas estas filosofías de diseño se reducen a decir "no rezo por diseñar un sistema flexible, así que no perdamos el tiempo intentando".
Mark
17

Cualquier idioma puede ser adecuado para un sistema integrado. Integrado 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 solicita un sistema (difícil) en tiempo real o de recursos limitados .

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

Para sistemas muy limitados en recursos (chips de 8 bits, menos de unos pocos Kb de RAM, sin pila accesible), C ++ completo podría no ser adecuado, aunque aún podría usarse como una '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 con un lenguaje que ya era un desastre serio para empezar. (Editar: el desorden grave es, por supuesto, C. Pascal es un lenguaje hermoso pero 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ó en referencia a esta, así que agregaré lo que escribí:

Nunca hay una razón general 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. Las discusiones sobre esto se pueden encontrar en muchos lugares, con posiciones que van desde "nunca use C ++ para un microcontrolador" hasta "siempre use 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 C ++ son más raros que los compiladores C; para algunos objetivos (por ejemplo, PIC de núcleo de 12 y 14 bits) no hay compiladores de C ++.
  • (bueno) los programadores de C ++ son más raros que los (buenos) programadores de C, especialmente entre aquellos que también tienen (algo) conocimiento 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 características que son inapropiadas para sistemas pequeños y, por lo tanto, no se pueden usar en sistemas pequeños.
  • C ++ tiene más construcciones que C que te permiten dispararte en el pie.
  • C ++ tiene más construcciones que C que te permiten evitar dispararte en el pie (sí, IMO 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 las 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 ver la máquina generada y, por lo tanto, el costo en espacio y tiempo de una construcción de lenguaje.
  • La construcción del lenguaje C ++ hace que sea menos necesario ser consciente de cómo se traducen exactamente al código de la máquina porque hacen "lo correcto" de una manera más abstracta.
  • El estándar de lenguaje C ++ está evolucionando rápidamente y es adoptado rápidamente por los grandes compiladores (gcc, clang, microsoft). C está evolucionando bastante lentamente, y la adopción de algunas características más nuevas (matrices variantes) es aterradora 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 nítida que C. ¿Confía en que sus programadores (o usted mismo) usen dicha herramienta para hacer una escultura hermosa, o temen que se lastimen y prefieren conformarse con un producto menos hermoso pero de menor riesgo? ? (Recuerdo que mi maestro de escultura me dijo una vez que las herramientas contundentes en algunas situaciones pueden ser más peligrosas que las afiladas).

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

Wouter van Ooijen
fuente
15

En mi experiencia, C ++ generalmente no es adecuado para pequeños sistemas integrados. Por lo que quiero decir, microcontroladores y dispositivos sin sistema operativo.

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

STL y Boost realmente demuestran el poder de C ++, ambos tienen una gran huella.

C ++ alienta al programador a abstraer la máquina, donde en sistemas restringidos debe ser aceptada.

El año pasado, porté 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 que funcione en entornos WinCE, Symbian y sin sistema operativo, una reescritura de C fue la opción más sensata.

Toby Jaffey
fuente
Estoy de acuerdo en referencia a sistemas pequeños, pero creo que tenemos diferentes definiciones de sistemas pequeños. Cuando tienes 1kB de ROM y un código C bien escrito toma todos menos 1 byte de ROM, ese es un sistema pequeño.
Kortuk
66
No estoy argumentando que C no puede tener una huella más pequeña, pero podría haber usado C ++ aún y obtener un resultado muy similar para diseñar para lo que se acaba de discutir. Creo que el problema es que la mayoría de los programadores de 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.
Kortuk
44
Entonces, ¿qué estás diciendo 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 la gente que usa C ++ solo porque está disponible, no porque sea óptima. Casi cualquier lenguaje es capaz de producir un código bueno y rápido, es cuestión de cómo se usa. La mayoría de las guerras santas sobre 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, lo cual es realmente un argumento idiota: p
Mark
2
"La mayoría de las guerras santas sobre los idiomas no son el resultado de las capacidades de los idiomas, sino un argumento sobre lo fácil que es para un idiota hacer cosas idiotas, lo cual es realmente un argumento idiota". Fue una frase muy agradable. Necesito tu apellido para poder citarlo.
Kortuk
1
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.
Kortuk
11

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

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 mayor que la RAM disponible y ciertamente es un desperdicio en los microcontroladores. Para más información ver n4049 y n4234 . Deben estar apagados (que actualmente es un comportamiento no especificado, así que asegúrese de no tirar nunca). SG14 está trabajando actualmente en mejores formas de hacerlo.

  • RTTI probablemente nunca valga la pena la sobrecarga, debe apagarse

  • Grandes construcciones de depuración, 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 de código con plantilla o llamadas de función adicionales agregadas para mayor claridad. El optimizador eliminará nuevamente estas llamadas de función adicionales y la claridad o flexibilidad añadidas puede ser una gran ventaja, sin embargo, en las versiones de depuración esto puede ser un problema.

  • Asignación de montón. Aunque el STL permite el uso de asignadores personalizados, esto puede ser complejo para la mayoría de los programadores. La asignación del montón no es determinista (es decir, no es difícil en tiempo real) y la fragmentación puede provocar 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 objetos pequeños. Por lo general, es mejor usar la asignación de grupo (tanto en C como en C ++), pero esto puede ser anormal para los programadores de C ++ que solo usan el montón.

  • El polimorfismo de tiempo de ejecución y otras llamadas indirectas suelen ser un gran impacto en el rendimiento, el problema suele ser mayor porque el optimizador no puede ver a través de ellos más que la búsqueda y el salto reales a la dirección. Las llamadas indirectas se deben evitar por esta razón en C y C ++, donde, como 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 contradictorio que los problemas de clib se encuentren en la categoría C ++, pero el problema surge de la compartición implícita de recursos en entornos concurrentes (la compartición es más explícita en C). El uso de la implementación común de newLib a menudo arrastra una gran cantidad de hinchazón que generalmente no es necesaria en uC, por otro lado, newLibNanno no es reentrante, por lo que el acceso a él debe ser serializado (simplificando demasiado aquí). Este también es un problema para C, pero el acceso es más explícito. Como regla general, uno esencialmente no debe usar nada del espacio de nombres estándar en el contexto ISR a menos que esté seguro de que de alguna manera no accede al estado en clib (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 esencialmente todos son 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 adecuadamente las cosas de una manera que el usuario no necesite saber cómo funcionan para usarlas y la mayoría 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 los 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 la posible generación de código muerto y la pérdida del potencial de optimización.

Sé que puedo estar desatando una tormenta de mierda aquí, pero mi experiencia en microcontroladores de 32 bits es que en una comparación de manzanas a manzanas de C y C ++, ambas escritas por expertos (como en C ++ potencialmente muy tentado) 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 experto de bibliotecas en C ++.

Al mismo tiempo, hay realmente pocas funciones a las que no puedo pasar datos incorrectos, tan pronto como la entrada no es un int, pero somethingpara el que estoy usando un int como método de representación, entonces existe la posibilidad de obtenerlo incorrecto (pase un valor no válido o un 'otroThing' 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, pero algunas comprobaciones en tiempo de compilación que son gratuitas.

Al final del día, un equipo C a menudo es 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 un solo trabajo único en un entorno único de decisiones de diseño únicas o es lo suficientemente genérico como para ser utilizado 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 a un costo cero. Aquí tenemos mucho menos intercambio entre ser genérico y ser rápido y, por lo tanto, desde un punto de vista de costo versus beneficio, el lenguaje más productivo, más seguro y más productivo.

Es una crítica válida que todavía hay una gran escasez de buenas bibliotecas de C ++ para embebido, esto puede llevar a decisiones pragmáticas para usar principalmente C en un compilador de C ++. Las decisiones de usar solo C en un proyecto están esencialmente motivadas ideológicamente, por necesidad de soporte heredado o por admitir que el equipo no es lo suficientemente disciplinado como 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 cosas estúpidas mucho más grandes de las que no se puede protegerse en C pero sí en C ++.

odinthenerd
fuente
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!
Wouter van Ooijen
Ah sí actualizado perfil;) bueno saber su venir a EMBO ++ será una buena gente
odinthenerd
10

Mi experiencia: recién salido de la escuela bajo viejos programadores de Bell Labs; estado trabajando durante 3 años, 2 en proyectos 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 un proyecto para PC integrado con 2 GB de almacenamiento, 512 MB de RAM, 500 MHz x86 CPU; varias aplicaciones que se ejecutan simultáneamente escritas en C ++ con un mecanismo IPC en el medio. Si soy joven

Mi opinión: creo que C ++ puede funcionar eficazmente 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, 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 válido C es válido C ++, C ++ es un lenguaje muy diferente y uno necesita aprender a programar en C ++, no C, para usarlo efectivamente en cualquier situación. En C ++, debe programar orientado a objetos, no de procedimiento, y no un híbrido de los dos (grandes clases con muchas funciones). En general, debe enfocarse en hacer 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 de manera procesal en objetos, lo cual es un gran desastre y es difícil de mantener. Cuando comencé a aplicar más técnicas orientadas a objetos, descubrí que la capacidad de mantenimiento / legibilidad de mi código aumentó.

  • C ++ proporciona características adicionales en forma de desarrollo orientado a objetos que pueden proporcionar una forma de simplificar el código para que sea más fácil de leer / mantener . Honestamente, no creo que haya mucho en el camino de una mejora en el rendimiento / eficiencia del espacio al hacer POO. Pero creo que OOP 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 contra C ++ tienen que ver principalmente con la asignación dinámica de memoria. 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 una manera fácil. Al igual que en C, debe tener cuidado sobre cómo administrar los datos para reducir las pérdidas de memoria, pero la técnica RAII lo hace más simple en C ++ (haga que la memoria dinámica se destruya automáticamente al encapsularla en objetos). En algunas aplicaciones, donde cada ubicación de memoria cuenta, esto puede ser demasiado salvaje y lanudo para administrar.

EDITAR:

  • WRT la pregunta "Arduino C ++" : Yo diría que C ++ sin administración de memoria dinámica 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 que una aplicación con todos los datos asignados en el stack aún puede ser útil con objetos. Sin embargo, lo admitiré: nunca escribí una aplicación incrustada como esa para Arduino, por lo que no tengo pruebas de mi reclamo. Tengo algunas oportunidades para desarrollar Arduino en un próximo proyecto, espero poder probar mi reclamo allí.
J. Polfer
fuente
2
Me gustaría comentar sobre su segundo punto, usted dice que ayuda a dividir un problema complejo en muchas piezas pequeñas y que esa característica debe ignorarse. Esta es la razón exacta por la que soy tan pro-C ++. Un gran cuerpo de investigación en programación muestra que un crecimiento lineal en el tamaño del programa da un crecimiento exponencial en el tiempo de desarrollo. esto sigue el camino opuesto, si puede dividir correctamente un programa, puede dar una disminución exponencial en el tiempo de desarrollo. Esto es, con mucho, lo más importante.
Kortuk
en su segundo punto también: el simple uso de una metodología de diseño OOP no produce más código compartimentado. Tener un buen diseño base lo hace, 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.
Mark
Eso siempre es cierto. Nunca he oído hablar de un lenguaje que imponga un buen diseño. Creo que en su mayoría implicamos que es el trabajo de los desarrolladores y que C ++ hace que sea fácil de usar e implementar de manera organizada.
Kortuk
@ Mark - Estoy de acuerdo. Ha sido un proceso de aprendizaje para mí.
J. Polfer
7

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 tan cercano a los límites de sus sistemas como un aumento en 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 ++ les da a los programadores un lugar para un método de desarrollo muy estructurado y controlado. Hay un costo para aprender OOP, y si desea cambiarlo, lo acepta y, en muchos casos, la administración 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 dinámica de la memoria es el demonio. En realidad no, el demonio es el enrutamiento automático, la administración dinámica de 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 embebido continúa funcionando durante 5 años, la gestión dinámica de la memoria puede realmente estropearse y comenzar a fallar. Ganssle discute cosas como apilar y apilar en su artículo.

Hay algunas cosas en C ++ que son más propensas a causar problemas y utilizan muchos recursos, por lo que eliminar la administración dinámica de la memoria y las plantillas son pasos importantes para mantener la huella de C ++ más cerca de la huella de C. Esto sigue siendo C ++, no necesita dinámica gestión de memoria o plantillas para escribir bien 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 de que se ha detectado una excepción.

revs Kortuk
fuente
1
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 el número de pines IO.
Wouter van Ooijen
El argumento sobre la memoria dinámica es la OMI más importante. 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.
Dmitry Grigoryev
6

Pensé que este discurso anti-C ++ de Linus Torvalds era interesante.

Una de las peores características absolutas de C ++ es cómo hace que muchas cosas sean tan dependientes del contexto, lo que solo significa que cuando mira el código, una vista local rara vez ofrece 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 recordarlas cuando tenga que actualizar el código en unos pocos 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 potente como para ser llamado PC Hace 10 años.)

pingswept
fuente
55
Podemos ser diferentes, pero me parece que al abrir cualquier proyecto no puedo decir qué está sucediendo de inmediato, pero si sé algo sobre lo que está haciendo y tengo algo bien codificado en C y algo bien codificado en C ++, C ++ siempre parece más claro. Aún necesita implementar la encapsulación para un buen desarrollo en C, que C ++ hace muy fácil de hacer. El uso adecuado de las clases puede dejar muy claro dónde están sus interfaces, y se pueden manejar completamente a través de un objeto.
Kortuk
Totalmente acordado en encapsulación y clases. Sobrecarga del operador y herencia, no tanto.
pingswept
1
Jaja, sí, la sobrecarga del operador se puede utilizar 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 similar al padre con algunas adiciones. Creo que no usaría todas las funciones en OOP. He usado ambos, pero en un sistema embebido no puedo pensar en un caso donde lo haría. Del mismo modo que creo que un compilador con un límite de 80 caracteres en los nombres de variables debería ser descartado inmediatamente.
Kortuk
2
Solo
vomité
No eres el único, pero si funciona bien y es eficiente, puedo perdonar.
Kortuk
6

Creo que otras respuestas hicieron un buen caso para 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 que te hagas daño, no hay ganancia y renunciarás a demasiados recursos.

Para microcontroladores de alta gama (por ejemplo, 32 bits, 10 o 100 MB de RAM para almacenamiento y RAM) 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 que desarrollé un sistema para una uC de 16 bits con 1 MB de RAM y 1 MB de almacenamiento en C ++, solo para lamentarlo más tarde. Sí, funcionó, pero el trabajo extra que tenía no valía la pena. Tenía que ajustarlo, asegurarme de que cosas como las excepciones no produjeran fugas (el soporte OS + RTL era bastante defectuoso y poco confiable). Además, una aplicación OO generalmente realiza muchas asignaciones pequeñas, y la sobrecarga del montón para esas fue otra pesadilla.

Dada esa experiencia, asumiría para proyectos futuros que 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á de acuerdo con el tipo de aplicación, estilos de codificación y modismos, etc. Pero dadas las advertencias, recomendaría un enfoque similar.

fceconel
fuente
2
Tengo que estar en desacuerdo aquí, no es un punto repentino donde C ++ se vuelve aceptable debido a los recursos del sistema, una buena práctica de diseño puede 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.
Kortuk
1
Bueno, depende de qué tan grande sea su aplicación y cuánto use ciertas características que requieren más espacio (como plantillas y excepciones). Pero personalmente prefiero usar C que limitarme a un C ++ restringido. Pero incluso entonces tendrá la sobrecarga de un RTL más grande, thunks de método virtual, invocación de la cadena constructor / destructor ... estos efectos pueden mitigarse con una codificación cuidadosa, pero luego está perdiendo la razón principal del uso de C ++, abstracción y Perspectiva de alto nivel.
fceconel
4

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

Si tuviera mis habilidades, habría un lenguaje popular que combinaría lo mejor de ambos mundos e incluiría algunas características que faltan en ambos idiomas; 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 el requisito de 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 entero arbitrario si tiene éxito, pero también puede fallar. Muchas plataformas podrían manejar esto de forma económica en código, por ejemplo, teniendo el valor de retorno en un registro y la indicación de éxito / falla en el indicador de acarreo.
  2. Sobrecarga de funciones estáticas y en línea solamente; Tengo entendido que los organismos de normalización para C han evitado la sobrecarga de funciones para evitar la necesidad de alterar el nombre. Permitir sobrecargas de funciones estáticas e inline 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 inline 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 de manera muy eficiente 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:
    inline void copy_uint32s (uint32_t * dest, const uint32_t * src, __is_const int n)
    {
      si (n <= 0) devuelve;
      si no (n == 1) {dest [0] = src [0];}
      si no (n == 2) {dest [0] = src [0]; dest [1] = src [1];}
      si no (n == 3) {dest [0] = src [0]; dest [1] = src [1]; dest [2] = src [2];}
      si no (n == 4) {dest [0] = src [0]; dest [1] = src [1]; dest [2] = src [2]; dest [3] = src [3];}
      else memcpy ((void *) dest, (const void *) src, n * sizeof (* src));
    }
    
    Si 'n' se puede evaluar en tiempo de compilación, el código anterior será más eficiente que una llamada a memcpy, pero si 'n' no se puede evaluar 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á demasiado interesado en una versión de C ++ solo incrustada, pero creo que podría ofrecer algunas mejoras considerables con solo usar C.

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

supercat
fuente
@Joby Taffey: creo 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, realmente no habían llegado tan lejos. Creo que habrá un uso definitivo para un lenguaje estandarizado que sea apto para 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 # 3 arriba? Parecería muy útil, pero nunca he visto ningún idioma que lo ofrezca.
supercat
"El padre de C ++" tiene cero experiencia en programación de sistemas integrados, entonces, ¿por qué a alguien le importaría su opinión?
Lundin
@Lundin: El hecho de que algunas personas influyentes parecen preocuparse por sus opiniones sobre diversos asuntos parece ser una razón, en sí misma, para que otras personas lo hagan. Estoy pensando que, desde que escribí lo anterior, el creciente poder de las plantillas puede haber agregado nuevas posibilidades para tener sobrecargas basadas en qué constantes se pueden resolver en tiempo de compilación, aunque mucho menos limpiamente que si tal cosa se admitiera como una 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 ...
supercat
... pero eso requeriría que el compilador desperdiciara un poco de esfuerzo compilando posibles sustituciones que luego terminarían siendo descartadas. Ser capaz de decir con mayor claridad "Si esto es una constante, hacer esto; de lo contrario, hacer esto" sin ningún "comienzo falso" parecería un enfoque más limpio.
supercat
3

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 características se pueden usar por separado, los mejores resultados se logran cuando las tres se usan al mismo tiempo. No obstante, si elige elegir solo uno de ellos, la calidad del software incorporado aumentará.

a) Es una "mejor" C

C ++ es un lenguaje tipado fuerte; 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 incurrió 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. ¡Incorrecto! Todos nosotros, los ingenieros integrados, siempre hemos abstraído la máquina, solo con otro sintaxis que el de C ++. El problema que veo con este argumento es que algunos programadores no están acostumbrados a pensar en objetos, así no ven los beneficios de la POO.

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

/ * Configuración del temporizador para partido 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 ++, ¡a costo cero!

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

Los programas genéricos se logran mediante 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.

Existe 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 usando 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 los 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 embebidos. ¡Evítalos a toda costa!

fjrg76
fuente
2

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

Contenido de llama

¿C ++ es adecuado para sistemas integrados?

Meh C ++ es un dolor para escribir y un dolor para mantener. C + está bastante bien (no use algunas funciones)

C ++ en microcontroladores? RTOSes? Tostadoras? PC integradas?

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

¿OOP es ú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 ++ elimina el programador demasiado lejos del hardware para ser eficiente?

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

Ve a buscar un MCU que ejecute bytecodes de Java. Programa en Java. Ríete de los chicos de C.

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

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

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

Tim Williscroft
fuente
2
¿Es tan fácil encontrar microcontroladores compatibles con Java? Creo que esto limitaría las opciones considerablemente. ¿Y cuáles son sus experiencias sobre la penalización del rendimiento (ya que en uC generalmente no tendría JIT)? ¿Qué pasa con el impacto de la imprevisibilidad de GC en sistemas en tiempo real?
fceconel
2
¿Qué MCU existen que admitan Java incrustado?
J. Polfer
www.ajile.com para empezar.
Tim Williscroft
+1 para Ada. Tiene mucho que ver con embebido, incluido Arduinos.
Brian Drummond
Java VM portátil para micros escrito en c es de código abierto. dmitry.co/index.php?p=./04.Thoughts/…
Tim Williscroft
-2

Los sistemas integrados están diseñados para realizar una tarea específica, en lugar de ser una computadora de uso general para múltiples tareas. Un sistema integrado es una combinación de hardware y software de computadora. C es la madre de todos los lenguajes modernos. Es un lenguaje completo de bajo nivel pero potente y ofrece 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 en desarrollo. El sistema operativo UNIX está escrito en C. Debido a que el desarrollo exitoso de software consiste en seleccionar el mejor idioma 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, que permite a los programadores concentrarse en algoritmos y aplicaciones, en lugar de en los detalles de la arquitectura particular del procesador. 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?

IMRAN AHMAD AWAN
fuente
66
Realmente no estoy seguro de lo que esto agrega a la discusión.
Dave Tweed
-3

<rant>

Creo que C ++ es un lenguaje malo en primer lugar. Si desea usar OOP, escriba programas Java. C ++ no hace nada para imponer paradigmas de OOP, ya que el acceso directo a la memoria está totalmente dentro de su poder para (ab) usarlo.

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

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

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

</rant>

vicatcu
fuente
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?
Kortuk
1
No lo rechacé, pero me gustaría señalar que C ++ no necesita imponer OOP, solo da 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.
Kortuk
1
Todos los idiomas son buenos 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 lo desconocido. Creo que es por eso que tiene tanta tracción en el desarrollo del juego.
Toby Jaffey
1
Sí estoy de acuerdo. La razón por la que lo veo para el mundo incrustado se debe a la gran cantidad de características y funciones que se agregan a muchos de los diferentes sistemas ya existentes y a los nuevos sistemas que se están desarrollando. Proyecto cada vez más grande. O tomamos más tiempo para desarrollarlos o comenzamos a aplicar y retorcer lo que el mundo CS ya ha hecho en las PC.
Kortuk
55
Sin embargo, otra persona que no entiende C ++ correctamente. Siempre me sorprende cuántos hay.
Rocketmagnet