¿Por qué C domina en el mercado de software embebido? [cerrado]

14

Casi todos dirán ahora la bendición:

rendimiento !

De acuerdo, C permite escribir código atlético. ¡Pero hay otros idiomas que pueden hacerlo, después de todo! Y el poder de optimización de los compiladores modernos es impresionante. ¿ C tiene algunas ventajas que ningún otro lenguaje tiene? ¿O simplemente no hay necesidad de instrumentos más flexibles en el dominio?

vides
fuente
1
FWIW, Arduino se puede controlar con C #: arduino.cc/playground/Interfacing/Csharp
FrustratedWithFormsDesigner
@ Frustrado: Sí, pero ese es un ejemplo, y la mayoría de las personas que construyen dispositivos están usando Arduino.
Ed S.
2
Ver también: stackoverflow.com/questions/812717/…
Steve Melnikoff
1
@ dan04, en la gran mayoría de los casos, eso no fue realmente un problema. Un grupo de simulación 6DOF en el Grupo de Electrónica y Sistemas de Defensa de Texas Instruments hizo un pequeño experimento alrededor de 1988. Hasta entonces, habían hecho todas sus simulaciones en FORTRAN. Intentaron escribir uno en PASCAL, para ver qué tanto le dolería. Descubrieron que PASCAL les dio un pequeño éxito en el rendimiento, pero el aumento en la confiabilidad y la facilidad de depuración MÁS de lo compensó. Sin rodeos, descubrieron que la verificación de tipo fuerte de PASCAL era algo BUENO. (Y sí, estaban haciendo matrices.)
John R. Strohm

Respuestas:

41

Casi todos dirán ahora la bendición:

¡actuación!

Eso es parte de eso; El uso determinista de recursos es importante en dispositivos con recursos limitados para empezar, pero hay otras razones.

  1. Acceso directo a API de hardware de bajo nivel.
  2. Puede encontrar un compilador de C para la gran mayoría de estos dispositivos. Esto no es cierto para ningún lenguaje de alto nivel en mi experiencia.
  3. C (el tiempo de ejecución y el ejecutable generado) es "pequeño". No tiene que cargar un montón de cosas en el sistema para ejecutar el código.
  4. Las API / controladores de hardware probablemente se escribirán en C o C ++.
Ed S.
fuente
14
+1 Disponibilidad de compiladores. Cuando estábamos escribiendo todo en ensamblador, los compiladores de la primera generación fueron enviados por Dios.
Christopher Bibbs
8
+1, creo que el uso determinista de recursos es una de las razones más importantes. No tienes mucha memoria para hacer todo tipo de recolección de basura elegante en un lavavajillas.
user281377
44
+1 también para "uso de recursos determinista". En muchos sistemas integrados, este requisito incluso impide el uso de la asignación de memoria dinámica. Muchos otros lenguajes dependen en gran medida de la asignación de memoria dinámica (incluso muchos aspectos beneficiosos de C ++ necesitan memoria dinámica).
Michael Burr
2
Añadiría una viñeta más, que resulta ser una razón social más que técnica: creo que los desarrolladores de software embebidos tienden a ser mucho más conservadores y resistentes al cambio que otros desarrolladores. Dependiendo de su punto de vista, esto podría ser algo bueno o malo.
Michael Burr
1
Hablando como un tipo de sistemas, desconfío de las grandes abstracciones. Son geniales, hasta que dejan de funcionar o hacen algo divertido, en cuyo caso puede ser un gran dolor de cabeza depurar. Eso no es algo que quiera en un sistema de bajo nivel.
Ed S.
18

C fue diseñado para modelar una CPU, porque C fue creado para hacer que Unix sea portátil en todas las plataformas en lugar de solo escribir lenguaje ensamblador.

Esto significa que los programas C funcionan bien como un lenguaje de programación para programas que necesitan tener un nivel de abstracción muy cercano a la CPU real, como es el caso del hardware incorporado.

Nota: C fue diseñado alrededor de 1970 y las CPU eran más simples entonces.


fuente
3
+1: Esta es definitivamente la razón. Tal vez la gente ha intentado diseñar lenguajes de alto nivel más nuevos que capturen las características de los procesadores modernos, pero nadie ha diseñado un lenguaje para eso.
Ken Bloom
2
@vines, C es un lenguaje pequeño con una gran biblioteca de tiempo de ejecución. Todo esto se puede hacer en la biblioteca de tiempo de ejecución. Simplemente no migrará automáticamente a la biblioteca C estándar, por lo que es específica de la plataforma.
3
+1. C fue creado para, e inicialmente utilizado en un PDP-7, que tenía un máximo de 64kilowords de palabras de 18 bits. Muchos más idiomas "modernos" tienen más dificultades para adaptarse a ese tipo de espacio. Especialmente para escribir un sistema operativo como Unix.
greyfade
2
@greyfade: no es así. UNIX se originó en el PDP-7, pero C no. Para citar el prefacio del lenguaje de programación C : "C fue diseñado e implementado originalmente en el sistema operativo UNIX en el DEC PDP-11, por Dennis Ritchie".
Jerry Coffin
1
@vines: si bien es razonable contemplar el soporte directo para el subproceso en el lenguaje (cf, concurrente C), gran parte del punto de un caché es que hace las cosas más rápidas sin ninguna intervención del programador o lenguaje.
Jerry Coffin
11

Una razón para la dominación es que tiene el tipo correcto de herramientas para la tarea. Después de haberse desarrollado en plataformas integradas tanto en Java como en C / C ++, puedo decirle que el enfoque básico de C ++ es simplemente más natural. Salvar al desarrollador de la sensación de que él o ella está saltando a través del aro porque el lenguaje es demasiado alto es algo bastante molesto. Un buen ejemplo es la ausencia de variables sin signo en Java.

Y las funciones prácticas de VM / lenguajes interpretados generalmente no son factibles y quedan fuera de la implementación, por ejemplo, recolección de basura.

celebrador
fuente
3
"Java y C / C ++": espero que haya querido decir "los tres: Java C y C ++", ya que C y C ++ son lenguajes diferentes.
Bћовић
1
@ BЈовић: respondiendo años más tarde para confirmar que sí, que me refería a los tres. Fui usign ambos siguiendo esta definición: "utilizado como una palabra de función para indicar y enfatizar la inclusión de cada una de dos o más cosas" (dos o más cosas) :-)
celebrador
10

C requiere muy poco soporte de tiempo de ejecución en sí mismo, por lo que la sobrecarga es mucho menor. No está gastando memoria o almacenamiento en soporte de tiempo de ejecución, gastando tiempo / esfuerzo para minimizar ese soporte, o tener que permitirlo en el diseño de su proyecto.

geekosaur
fuente
1
¿Realmente nunca sucede que necesita esa funcionalidad y la reinventa usted mismo? Por ejemplo, las máquinas de estado grandes construidas con switches son horribles, y las mismas máquinas construidas con jerarquías de clase son agradables y fáciles de mantener.
vides
1
@vines: normalmente tiene un conjunto definido de entradas, máquinas de estado construidas en el interruptor / si las escaleras son más claras y documentables que una heiracrchy de llamadas polimórficas "detrás de escena" mágicas.
Martin Beckett
2
@ Martin: para alguien con poca experiencia en el desarrollo de OO, las llamadas polimórficas no son "mágicas" ni "detrás de escena", y la noción de que las declaraciones de cambio / si son más claras y más documentables parece completamente extraña.
Michael Borgwardt
3
Encuentra lo que sucede cuando pin27 sube. Opción 1, busque "caso PIN27:" La opción 2 rastrea un iterador sobre un mapa de functores para descubrir cuál se llamaría para los objetos PIN asignados al pin 27 en tiempo de ejecución. El problema con una gran cantidad de código OO es que la única forma de leerlo es esencialmente ejecutarlo. En una plataforma sin depuración en tiempo de ejecución o incluso una consola que significa rastrear el código en papel o en la cabeza.
Martin Beckett
2
Ligeramente tangente a esta discusión, hay una razón por la que la lógica de escalera (una versión aún más primitiva de switch, se podría decir) todavía se usa en muchas aplicaciones integradas. Más fácil de depurar, más fácil de verificar.
geekosaur
9

Como se mencionó en otras respuestas, C se desarrolló a principios de la década de 1970 para reemplazar el lenguaje ensamblador en una arquitectura de minicomputadora. En aquel entonces, estas computadoras generalmente cuestan decenas de miles de dólares, incluida la memoria y los periféricos.

Hoy en día, puede obtener la misma o mayor potencia de la computadora con un microcontrolador integrado de 16 bits que cuesta cuatro dólares o menos en cantidades individuales, incluidos los controladores de E / S RAM incorporados. Un microcontrolador de 32 bits cuesta quizás un dólar o dos más.

Cuando estoy programando a estos pequeños, que es lo que hago el 90% del tiempo cuando no estoy diseñando los tableros en los que se sientan, me gusta visualizar lo que el procesador va a hacer. Si pudiera programar lo suficientemente rápido en ensamblador, lo haría.

No quiero todo tipo de capas de abstracción. A menudo depuro revisando una lista de diseminadores en la pantalla. Para empezar, es mucho más fácil hacerlo cuando has escrito el programa en C.

tcrosley
fuente
1
Para algunas aplicaciones integradas, ese "dólar o dos más" es muy significativo. Nadie notará el impacto en el precio de su automóvil, pero sí en su termostato o reproductor de CD.
David Thornley
3
@David Thornley, sí, estoy completamente de acuerdo, es por eso que actualmente tengo proyectos en marcha con micros de 8, 16 y 32 bits al mismo tiempo para diferentes clientes. (El consumo de energía es otra razón para ir con los dispositivos más pequeños.)
tcrosley
1
El precio está determinado menos por el costo del procesador que el recuento de pines. Los tableros son mucho más caros que los chips.
Yttrill
7

No domina por completo, ya que C ++ se usa cada vez más a medida que los compiladores han mejorado y el rendimiento del hardware ha aumentado. Sin embargo, C sigue siendo muy popular por algunas razones;

  1. Amplio soporte. Casi todos los proveedores de chips proporcionan un compilador de CA y cualquier código de ejemplo y controladores probablemente se escribirán en c. Los compiladores de C ++ son cada vez más comunes, pero no son un certificado muerto para un chip dado, y a menudo son más defectuosos. También sabe que cualquier ingeniero integrado podrá trabajar en c. Es la lengua franca de la industria.

  2. Actuación. Sí, lo dijiste. El rendimiento sigue siendo el rey y en un entorno donde las rutinas centrales todavía se escriben a menudo en ensamblador, o al menos se optimizan en c con referencia a la salida del ensamblaje, nunca subestimes la importancia de esto. A menudo, los objetivos integrados tendrán un costo muy bajo y tendrán muy pocos recuerdos y pocos mips.

  3. Talla. C ++ tiende a ser más grande. Ciertamente, cualquier cosa que use el STL será más grande. Generalmente tanto en términos de tamaño del programa como en huella de memoria.

  4. Conservatismo. Es una industria muy conservadora. En parte porque los costos de la falla son a menudo más altos y la depuración a menudo es menos accesible, en parte porque no ha tenido que cambiar. Para un pequeño proyecto incrustado, c funciona bien.

Luke Graham
fuente
11
Mira, es el número 3 que parece ser uno de los mitos más frecuentes sobre C ++. Escriba un contenedor de tipo seguro para 5 tipos distintos en C y habrá causado al menos tanta "hinchazón" como el uso de un único contenedor STL en 5 tipos distintos. Los programadores de C evitan esto escribiendo contenedores en tipos opacos (void *). Comparar ESO con una plantilla STL es un error de categoría. Sin embargo, debo admitir que es una de las "razones" más comunes para preferir C.
Edward Strange
Estoy totalmente de acuerdo en que para replicar la funcionalidad completa en c terminas con la misma huella que c ++. La 'ventaja' de c es que te permite ser selectivo. En cualquier proyecto importante, preferiría usar c ++, pero a veces el hardware de destino está limitado a un punto en el que eso no es práctico. Habiendo dicho eso, el # 1 es realmente la razón principal en mi experiencia.
Luke Graham
6

Para sistemas embebidos, lo importante es el rendimiento . Pero como dijiste, ¿por qué C y no otro lenguaje performante?

Muchas personas hasta ahora han mencionado la disponibilidad de compiladores , pero nadie ha mencionado la disponibilidad de desarrolladores . Muchos más desarrolladores ya conocen C que, por ejemplo, OCaml.

Esos son los tres grandes.

BlueRaja - Danny Pflughoeft
fuente
6

El software incorporado es muy diferente.

En una aplicación de escritorio, las abstracciones y las bibliotecas le ahorran mucho tiempo de desarrollo. Tiene el lujo de arrojar otro par de megabytes o gigabytes de RAM o algunos núcleos de CPU de 2 + GHz de 64 bits en un problema, y ​​otra persona (usuarios) está pagando por ese hardware. Es posible que no sepa en qué sistemas se ejecutará la aplicación.

En un proyecto integrado, los recursos suelen ser muy limitados. En un proyecto en el que trabajé (procesadores de la serie PIC 17X) el hardware tenía 2Kwords de memoria de programa, 8 niveles de pila (en hardware) y 192 bytes (<0.2kB) de RAM. Los diferentes pines de E / S tenían diferentes capacidades y usted configuró el hardware según sea necesario escribiendo en los registros de hardware. La depuración implica un osciloscopio y un analizador lógico.

En las incrustaciones, las abstracciones a menudo se interponen en el camino y gestionarían (y costarían) los recursos que no tiene. Por ejemplo, la mayoría de los sistemas integrados no tienen sistema de archivos. Los hornos de microondas son sistemas integrados. Controladores de motor de automóvil. Algunos cepillos de dientes eléctricos. Algunos auriculares con cancelación de ruido.

Un factor muy importante para mí en el desarrollo de sistemas embebidos es saber y controlar a qué se traduce el código en términos de instrucciones, recursos, memoria y tiempo de ejecución. A menudo, la secuencia exacta de instrucciones controla, por ejemplo, el tiempo para las formas de onda de la interfaz de hardware.

Las abstracciones y la "magia" detrás de escena (por ejemplo, un recolector de basura) es ideal para aplicaciones de escritorio. Los recolectores de basura le ahorran MUCHO tiempo persiguiendo pérdidas de memoria, cuando la memoria se puede / puede asignar dinámicamente.

Sin embargo, en el mundo embebido en tiempo real, necesitamos saber y controlar cuánto tardan las cosas, a veces en nanosegundos, y no podemos arrojar otro par de megas de RAM o una CPU más rápida a un problema. Un ejemplo simple: cuando se atenúa el software de los LED mediante el control del ciclo de trabajo (la CPU solo tenía el control de encendido / apagado de los LED), NO está bien que el procesador se apague y haga, por ejemplo, recolección de basura durante 100 ms porque la pantalla se vería visiblemente parpadea o se apaga.

Un ejemplo más hipotético es un controlador de motor que dispara directamente bujías. Si esa CPU se apaga y recolecta basura durante 50 ms, el motor se apagaría por un momento o se dispararía en la posición incorrecta del cigüeñal, lo que podría detener el motor (¿al pasar?) O dañarlo mecánicamente. Podrías matar a alguien.

Tecnófilo
fuente
Eso es tan cierto como irrelevante para C: el problema al que se refiere es solo el comportamiento del GC ... C ++ no tiene GC, y ¿sabe qué? Personalmente lo uso debido a los comentarios de línea y la seguridad de tipo más estricta =)
vides