Perché C domina nel mercato del software embedded? [chiuso]


14

Quasi tutti ora diranno la benedizione:

spettacolo !

Va bene, C permette di scrivere un codice atletico. Ma ci sono altre lingue che possono farlo, dopo tutto! E il potere di ottimizzazione dei compilatori moderni è eccezionale. Fa C ha alcuni vantaggi che nessun altro linguaggio è? O semplicemente non c'è bisogno di strumenti più flessibili nel dominio?


1
FWIW, Arduino può essere controllato con C #: arduino.cc/playground/Interfacing/Csharp
FrustratedWithFormsDesigner

@Frustrated: Sì, ma questo è un esempio e la maggior parte delle persone che costruiscono dispositivi utilizzano Arduino.
Ed S.



1
@ dan04, nella stragrande maggioranza dei casi, questo non era in realtà un problema. Un gruppo di simulazione 6DOF al Texas Instruments Defence Systems and Electronics Group ha fatto un piccolo esperimento verso il 1988. Fino ad allora, avevano fatto tutte le loro simulazioni in FORTRAN. Hanno provato a scriverne uno in PASCAL, per vedere quanto sarebbe stato male. Hanno scoperto che PASCAL ha dato loro un piccolo successo in termini di prestazioni, ma l'aumento dell'affidabilità e della facilità di debug PIÙ di quanto non abbia compensato. Senza mezzi termini, hanno scoperto che il forte controllo del tipo di PASCAL era una buona cosa. (E sì, stavano facendo array.)
John R. Strohm,

Risposte:


41

Quasi tutti ora diranno la benedizione:

prestazione!

Fa parte di esso; l'uso delle risorse deterministiche è importante per i dispositivi con risorse limitate all'inizio, ma ci sono altri motivi.

  1. Accesso diretto alle API hardware di basso livello.
  2. È possibile trovare un compilatore C per la stragrande maggioranza di questi dispositivi. Questo non è vero per nessun linguaggio di alto livello nella mia esperienza.
  3. C (il runtime e l'eseguibile generato) è "piccolo". Non è necessario caricare un sacco di roba nel sistema per far funzionare il codice.
  4. Le API / i driver hardware saranno probabilmente scritti in C o C ++.

14
+1 Disponibilità di compilatori. Quando stavamo scrivendo tutto in assemblea, i primi compilatori di gen erano un mittente.
Christopher Bibbs,

8
+1, penso che l'uso delle risorse deterministiche sia tra i motivi più importanti. Non hai molta memoria per fare tutti i tipi di fantasiosa raccolta di rifiuti in lavastoviglie.
user281377

4
+1 anche per "utilizzo delle risorse deterministico". Su molti sistemi embedded, questo requisito impedisce persino l'uso dell'allocazione dinamica della memoria. Molti altri linguaggi dipendono fortemente dall'allocazione dinamica della memoria (anche molti aspetti positivi del C ++ richiedono memoria dinamica).
Michael Burr,

2
Aggiungerei un altro punto elenco, che risulta essere una ragione sociale piuttosto che tecnica - penso che gli sviluppatori di software embedded tendano ad essere molto più conservatori e resistenti ai cambiamenti rispetto ad altri sviluppatori. A seconda del tuo punto di vista, questa potrebbe essere una cosa positiva o negativa.
Michael Burr,

1
Parlando come un ragazzo di sistemi, sono diffidente delle grandi astrazioni. Sono fantastici, fino a quando smettono di funzionare o fanno qualcosa di divertente, nel qual caso può essere un grosso mal di testa da debug. Non è qualcosa che voglio in un sistema di basso livello.
Ed S.

18

C è stato progettato per modellare una CPU, perché C è stato creato per rendere Unix portatile su più piattaforme invece di scrivere semplicemente un linguaggio assembly.

Ciò significa che i programmi C funzionano bene come linguaggio di programmazione per i programmi che devono avere un livello di astrazione molto vicino alla CPU effettiva, come nel caso dell'hardware incorporato.

Nota: C è stato progettato intorno al 1970 e le CPU erano più semplici di allora.


3
+1: questo è sicuramente il motivo. Forse le persone hanno provato a progettare linguaggi di alto livello più recenti che catturano le caratteristiche dei processori moderni, ma nessuno ha progettato un linguaggio per quello che è preso.
Ken Bloom,

2
@vines, C è un linguaggio di piccole dimensioni con una libreria di runtime di grandi dimensioni. Tutto ciò può essere fatto nella libreria di runtime. Semplicemente non migrerà automaticamente nella libreria C standard, quindi è specifico per la piattaforma.

3
+1. C è stato creato per, e inizialmente utilizzato su un PDP-7, che aveva un massimo di 64kiloword di parole a 18 bit. Molte più lingue "moderne" hanno più difficoltà ad adattarsi a quel tipo di spazio. Soprattutto per scrivere un sistema operativo come Unix.
Greyfade,

2
@greyfade: non è così. UNIX ebbe origine sul PDP-7, ma C no. Per citare dalla prefazione a The C Programming Language : "C è stato originariamente progettato e implementato sul sistema operativo UNIX su DEC PDP-11, da Dennis Ritchie".
Jerry Coffin,

1
@vines: mentre è certamente ragionevole considerare il supporto diretto per il threading nel linguaggio (cfr. Concurrent C), gran parte del punto di una cache è che rende le cose più veloci senza alcun intervento da parte del programmatore o del linguaggio.
Jerry Coffin,

11

Uno dei motivi del dominio è che ha il giusto tipo di strumenti per l'attività. Dopo aver sviluppato piattaforme embedded sia in Java che in C / C ++, posso dirti che l'approccio bare to the bone del C ++ è semplicemente più naturale. Salvare lo sviluppatore dal sentire che sta saltando attraverso i cerchi perché la lingua è di livello troppo alto è una cosa piuttosto fastidiosa. Un buon esempio è l'assenza di variabili non firmate in Java.

E le utili funzionalità della VM / dei linguaggi interpretati di solito non sono fattibili e sono escluse dall'implementazione, ad es. Garbage Collection.


3
"sia Java che C / C ++" - Spero che intendessi "tutti e tre: Java C e C ++", poiché C e C ++ sono linguaggi diversi.
BЈовић,

1
@ BЈовић: rispondere anni dopo per confermare che sì, intendevo dire tutti e tre. Stavo usando entrambi seguendo questa definizione: "usato come una parola funzione per indicare e sottolineare l'inclusione di ciascuna di due o più cose" (due o più cose) :-)
celebdor

10

C richiede di per sé un supporto di runtime molto ridotto, quindi l'overhead è molto più basso. Non stai spendendo memoria o spazio di archiviazione sul supporto di runtime, non stai impiegando tempo / sforzi per minimizzare tale supporto o non devi permetterlo nella progettazione del tuo progetto.


1
Non succede mai che hai bisogno di quella funzionalità e reinventala tu stesso? Ad esempio, le grandi macchine a stati costruite con switches sono orribili e le stesse macchine costruite con gerarchie di classi sono belle e mantenibili.
viti

1
@vines - normalmente hai un set definito di input, macchine a stati costruite su switch / se le scale sono più chiare e più documentabili di un'erede della magia chiamata polimorfica "dietro le quinte".
Martin Beckett,

2
@Martin: per qualcuno con una piccola esperienza nello sviluppo di OO, le chiamate polimorfiche non sono né "magiche" né "dietro le quinte", e l'idea che un enorme cambiamento / se le dichiarazioni siano più chiare e più documentabili sembra del tutto bizzarra.
Michael Borgwardt,

3
Trova cosa succede quando il pin27 diventa alto. Opzione 1, cerca "case PIN27:" L'opzione 2 traccia un iteratore su una mappa di funzioni per scoprire quale verrà chiamato per un oggetto PIN assegnato al pin 27 in fase di esecuzione. Il problema con molto codice OO è che l'unico modo per leggerlo è essenzialmente eseguirlo. Su una piattaforma senza debug di runtime o addirittura una console che significa tracciare il codice su carta o nella tua testa.
Martin Beckett,

2
Leggermente tangente a questa discussione, c'è un motivo per cui la logica ladder (una versione ancora più primitiva di switch, si potrebbe dire) è ancora utilizzata in molte applicazioni integrate. Più facile da eseguire il debug, più facile da verificare.
geekosaur,

9

Come menzionato in altre risposte, C è stato sviluppato nei primi anni '70 per sostituire il linguaggio assembly su un'architettura di minicomputer. Allora, questi computer in genere costano decine di migliaia di dollari, tra cui memoria e periferiche.

Al giorno d'oggi, puoi ottenere la stessa o maggiore potenza del computer con un microcontrollore incorporato a 16 bit che costa quattro dollari o meno in singole quantità, inclusi i controller RAM e I / O integrati. Un microcontrollore a 32 bit costa forse un dollaro o due in più.

Quando sto programmando questi ragazzini, che è quello che faccio il 90% delle volte quando non sto progettando le schede su cui siedono, mi piace visualizzare cosa farà il processore. Se potessi programmare abbastanza velocemente in assemblatore, lo farei.

Non voglio tutti i tipi di strati di astrazione. Spesso eseguo il debug passando attraverso un elenco di dissemblatori sullo schermo. È molto più facile farlo quando hai scritto il programma in C per cominciare.


1
Per alcune applicazioni integrate, quel "dollaro o due in più" è molto significativo. Nessuno noterà l'impatto dei prezzi sulla loro auto, ma lo faranno sul loro termostato o lettore CD.
David Thornley,

3
@David Thornley, sì, sono completamente d'accordo, ecco perché al momento ho progetti che vanno con micros 8, 16 e 32 bit tutti contemporaneamente per client diversi. (Il consumo di energia è un altro motivo per andare con i dispositivi più piccoli.)
Tcrosley

1
Il prezzo è determinato in meno dal costo del processore rispetto al conteggio dei pin. Le schede sono molto più costose delle chips.
Yttrill,

7

Non domina del tutto poiché il C ++ viene sempre più utilizzato poiché i compilatori sono migliorati e le prestazioni dell'hardware sono aumentate. Tuttavia C è ancora molto popolare per alcuni motivi;

  1. Ampio supporto. Praticamente ogni fornitore di chip fornisce compilatore ac e qualsiasi codice e driver di esempio saranno probabilmente scritti in c. I compilatori C ++ sono sempre più comuni, ma non rappresentano un dead dead per un determinato chip e sono spesso più potenti. Sai anche che qualsiasi ingegnere embedded sarà in grado di lavorare in c. È la lingua francese del settore.

  2. Prestazione. Sì, l'hai detto. Le prestazioni sono ancora re e in un ambiente in cui le routine di base sono ancora spesso scritte in assemblatore, o almeno ottimizzate in c con riferimento all'output dell'assemblaggio, non sottovalutano mai l'importanza di questo. Spesso gli obiettivi incorporati avranno un costo molto basso e avranno memorie molto piccole e pochi mips.

  3. Taglia. Il C ++ tende ad essere più grande. Certamente tutto ciò che utilizza STL sarà più grande. Generalmente sia in termini di dimensioni del programma che di ingombro della memoria.

  4. Conservatorismo. È un'industria molto conservatrice. In parte perché i costi del fallimento sono spesso più elevati e il debug è spesso meno accessibile, in parte perché non è necessario modificarlo. Per un piccolo progetto incorporato c fa bene il lavoro.


11
Vedi, è il numero 3 che sembra essere uno dei miti più diffusi sul C ++. Scrivi un contenitore sicuro per i tipi per 5 tipi distinti in C e avrai causato almeno "gonfiore" rispetto all'uso di un singolo contenitore STL su 5 tipi distinti. I programmatori C aggirano questo problema scrivendo contenitori su tipi opachi (void *). Il confronto di QUELLO con un modello STL è un errore di categoria. Devo ammettere però che è davvero uno dei "motivi" più comuni preferire C.
Edward Strange,

Sono pienamente d'accordo sul fatto che per replicare la piena funzionalità in c si finisce con lo stesso footprint di c ++. Il "vantaggio" di c è che ti permette di essere selettivo. Su qualsiasi progetto significativo preferirei usare c ++, ma a volte l'hardware di destinazione è limitato a un punto in cui ciò non è pratico. Detto questo, il numero 1 è davvero il motivo principale della mia esperienza.
Luke Graham,

6

Per i sistemi embedded, la cosa importante sono le prestazioni . Ma come hai detto, perché C e non un altro linguaggio performante?

Molte persone finora hanno menzionato la disponibilità di compilatori , ma nessuno ha menzionato la disponibilità degli sviluppatori . Molti più sviluppatori conoscono già C di, diciamo, OCaml.

Questi sono i tre biggie.


6

Il software incorporato è molto diverso.

Su un'app desktop, le astrazioni e le librerie ti fanno risparmiare molto tempo di sviluppo. Hai il lusso di lanciare un altro paio di megabyte o gigabyte di RAM o alcuni core della CPU a 64 bit a 2 + GHz a un problema e qualcun altro (utenti) sta pagando per quell'hardware. Potresti non sapere su quali sistemi verrà eseguita l'app.

In un progetto incorporato, le risorse sono spesso molto limitate. In un progetto su cui ho lavorato (processori serie PIC 17X) l'hardware aveva 2 parole chiave di memoria del programma, 8 livelli di stack (nell'hardware) e 192 byte (<0,2 KB) di RAM. Pin I / O diversi avevano capacità diverse e l'hardware è stato configurato secondo necessità scrivendo ai registri hardware. Il debug comporta un oscilloscopio e un analizzatore di logica.

In embedded, le astrazioni spesso si intromettono e gestiscono (e costano) le risorse che non hai. Ad esempio, la maggior parte dei sistemi embedded non ha file system. I forni a microonde sono sistemi integrati. Controller per motori auto. Alcuni spazzolini elettrici. Alcune cuffie con cancellazione del rumore.

Un fattore molto importante per me nello sviluppo di sistemi embedded è conoscere e controllare ciò a cui il codice si traduce in termini di istruzioni, risorse, memoria e tempi di esecuzione. Spesso l'esatta sequenza di comandi di istruzioni, ad es. Tempistica per le forme d'onda dell'interfaccia hardware.

L'astrazione e la "magia" dietro le quinte (ad es. Un garbage collector) sono eccezionali per le app desktop. I garbage collector ti fanno risparmiare MOLTO tempo a caccia di perdite di memoria, quando la memoria è / può essere allocata in modo dinamico.

Tuttavia, nel mondo embedded in tempo reale, dobbiamo sapere e controllare quanto tempo impiegano le cose, a volte fino a nanosecondi, e non possiamo lanciare un altro paio di megabyte di RAM o una CPU più veloce a un problema. Un semplice esempio: quando si esegue l'oscuramento software dei LED controllando il ciclo di lavoro (la CPU aveva solo il controllo on / off dei LED), NON è GIUSTO che il processore si spenga e esegua ad esempio la garbage collection per 100 ms perché il display sarebbe visibilmente lampeggia o si spegne.

Un esempio più ipotetico è un controller del motore che accende direttamente le candele. Se quella CPU si spegne e esegue la raccolta dei rifiuti per 50 ms, il motore si spegne per un momento o si spegne nella posizione errata dell'albero motore, potenzialmente arrestando il motore (mentre passa?) O danneggiandolo meccanicamente. Potresti far uccidere qualcuno.


È vero tanto quanto è irrilevante per C - il problema a cui ti riferisci è solo il comportamento del GC ... C ++ non ha GC e sai cosa? Lo uso personalmente a causa dei commenti di riga e del tipo più rigoroso safety =)
vitigni
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.