Perché i sistemi operativi fanno cose di basso livello in C e C ++? Perché non solo C ++?


20

Nella pagina Wikipedia per Windows , indica che Windows è scritto in Assembly per il bootloader e lo switcher di attività e C e C ++ per le routine del kernel.

IIRC, puoi chiamare le funzioni C ++ da un extern "C"blocco d. Posso usare C per le funzioni del kernel in modo che le app C pure possano usarle (simili printfe simili), ma se possono essere semplicemente racchiuse in un extern "C "blocco, perché il codice in C?


10
Hai visto i vari "Perché usare C quando c'è C ++?" domande qui? Questo non è necessariamente un duplicato di nessuno di essi, ma sono correlati.

1
"puoi chiamare funzioni C ++ da un blocco" C "esterno come C ++" Vuoi dire che puoi chiamare funzioni C ...?
Code-Guru,

@ Code-Guru no, perché l'unica differenza tra le funzioni C e C ++ esportate è la decorazione del nome e in C ++, l'aggiunta della thisvariabile
Cole Johnson l'

2
Lancia un'eccezione in un ISR e guarda cosa succede
James,

Ancora un'altra domanda C vs. C ++.
Machado,

Risposte:


31

È principalmente per ragioni storiche. Alcune parti del kernel di Windows sono state originariamente scritte in C, perché nel 1983, oltre tre decenni fa, quando Windows 1.0 è stato rilasciato , il C ++ è stato appena rilasciato. Ora queste librerie C rimarranno lì "per sempre", perché Microsoft ha reso la compatibilità con le versioni precedenti un punto di forza e riscrivere una versione compatibile con i bug delle parti C in C ++ richiede uno sforzo tremendo senza vantaggi effettivi.


+1, suppongo che sia la risposta più realistica (oltre al fatto che potrebbero esserci alcuni sviluppatori del kernel di Windows a cui semplicemente non piace C ++ o non si fidano dei compilatori C ++ per quella roba di basso livello). Guarda, ad esempio, qui stackoverflow.com/questions/520068/… , perché il kernel Linux è scritto in C.
Doc Brown,

@ back2dos - Anche se il loro codice C non verrà eliminato, ciò non significa che verrà utilizzato o non aggiornato. Vi garantisco che esiste almeno un metodo che fa qualcosa che è stato originariamente scritto e contenuto in una libreria C che è stata trasferita in una libreria C ++ in Windows 8
Ramhound,

8
Ho difficoltà a credere che ci sia del codice Windows 1.0 in una recente versione di Windows. Windows ME è stata l'ultima versione di Windows non basata sulla base di codice di Windows NT. E anche questo è stato in gran parte sostituito dal nuovo kernel RT (che, a quanto ho capito, non promette molto in termini di compatibilità con le versioni precedenti).
TMN il

@TMN: l'argomento è molto probabilmente corretta sia - Sono abbastanza sicuro sulla strada che da Win 1.0 vi erano un sacco di librerie scritte in C che sono ancora parte della corrente di base di codice Win8, e nessuno a MS vede qualsiasi vantaggio di riscriverli in C ++.
Doc Brown,

1
Non c'è quasi nessun codice che parli comunque al kernel di Windows. Fondamentalmente, solo i conducenti lo fanno. Le applicazioni di solito parlano all'API Win32 o, eventualmente, all'API POSIX.
MSalters l'

24

Come la maggior parte delle persone ha sottolineato, le ragioni sono di gran lunga storiche, ma c'è qualcos'altro che nessuno sta menzionando e credo che sia la ragione per cui le persone scrivono ancora codice C per basso livello.

C è un linguaggio piccolo nel senso che la specifica è (relativamente) breve. Il C ++ è enorme e questo è un eufemismo. Questo potrebbe non importare molto al programmatore (anche se penso che lo faccia), ma è estremamente importante se si desidera effettuare una verifica formale . Inoltre ci sono strumenti consolidati per l'analisi del codice C, che potrebbero aiutare a prevenire bug, ecc.

E questo è molto importante nel software incorporato, dove il costo di un bug che viene distribuito è estremamente elevato, rispetto al resto del settore (confronta il Web, dove puoi applicare immediatamente una patch a tutti gli utenti). Per non parlare del software mission-critical e roba medica.

Ci sono stati tentativi di spostare C dalla sua posizione dominante nella programmazione di basso livello con linguaggi che sono ancora migliori in questo, come BitC, ma finora non hanno avuto successo.


4
+1 Per menzionare il software mission-critical in puro C (ad es. Software aeronautico). Tuttavia, nel software medico viene utilizzato anche il C ++ (vengono utilizzati test approfonditi anziché una verifica formale, che sarebbe estremamente difficile in C ++).
Giorgio,

1
Inoltre, C ha un sottoinsieme sicuro di successo MISRA-C. Esistono equivalenti per C ++, ma non sono standard di fatto (ancora). La tendenza nella programmazione critica per la sicurezza è che anche le biblioteche e i compilatori saranno costretti a usare un sottoinsieme sicuro come MISRA. Riscrivere una versione compatibile MISRA-C ++ dell'intera libreria standard C ++ sarà molto probabilmente un incubo.

2
@Lundin Le linee guida MISRA non sono un sottoinsieme sicuro - hai ancora puntatori non elaborati e la maggior parte delle altre caratteristiche che rendono C non sicuro - si concentrano principalmente sul non usare o documentare comportamenti specifici dell'implementazione.
Pete Kirkham,

@PeteKirkham MISRA-C rileverà tutti i più classici bug puntatori e imporrà l'analisi statica. Gli standard di sicurezza del settore (IEC 61508 e altri) sembrano approvare MISRA-C come un sottoinsieme sicuro di C. Non ci sono molte altre utili alternative per il software mission-critical, a meno che non si scelga SPARK Ada, un linguaggio che pochi conoscono, con uno strumento limitato supporto.

2
Questo avrebbe dovuto essere selezionato come la migliore risposta in quanto è corretto. Altri che suggeriscono che C sia usato solo per ragioni storiche è di per sé isterico.
Rob,

15
  1. Il runtime C è molto più piccolo.
  2. La traduzione di C ++ in costrutti di livello inferiore è meno trasparente che in C. (Vedi riferimenti e vtables, per due esempi rapidi)
  3. C di solito ha un ABI stabile. C ++ di solito no. Ciò significa che, come minimo, l'interfaccia di chiamata di sistema dovrebbe essere in stile C. Inoltre, se desideri qualsiasi tipo di modulo dinamico, avere un ABI coerente aiuta molto.

+1 per (2) e (3). Non sono convinto con (1).
Thomas Eding,

7
@Thomas Eding: il runtime C ++ è costituito dal runtime C, oltre a funzionalità C ++ come eccezioni, RTTI e un altro allocatore di memoria. YMMV se questo conta tanto più grande. (E poi c'è la libreria standard ...)
wnoise l'

Ah, ho dimenticato le eccezioni e i nuovi / elimina pool. RTTI Non ho mai usato però: D
Thomas Eding l'

11

I motivi non sono tecnici. Un po 'di assemblaggio è inevitabile, ma non sono costretti a usare la C occasionale, lo vogliono . La mia azienda usa un proprio kernel proprietario, scritto quasi interamente in C ++, ma non abbiamo bisogno di supportare un'interfaccia C per il kernel come la maggior parte degli altri, perché il nostro kernel incorporato è compilato monoliticamente con le nostre applicazioni C ++. Quando hai un'interfaccia C, spesso è più facile scrivere il codice dell'interfaccia in C, anche se è possibile usarlo extern "C"per scriverlo in C ++.

Anche noi abbiamo un'infarinatura di file C, principalmente a causa di codice di terze parti. Il codice di basso livello di terze parti è quasi sempre fornito in C, perché è molto più facile incorporare il codice C in un'app C ++ rispetto al contrario.


6

Gli sviluppatori del kernel sono spesso il tipo di persone, che si sentono più felici, quando è immediatamente evidente dalla fonte, cosa fa effettivamente il codice.

Il C ++ ha molte più funzioni, che nascondono ciò che il codice fa di più rispetto al semplice codice C che lo nasconde: sovraccarichi, metodi virtuali, modelli, riferimenti, proiezioni ... Il C ++ ha anche molta più sintassi che devi padroneggiare per capire anche il C ++ codice che lo utilizza.

Penso che il potere del C ++ sia uno strumento molto potente per creare librerie e framework, che rendono lo sviluppo di applicazioni un gioco da ragazzi. Molto spesso lo sviluppatore di applicazioni C ++ verrebbe totalmente perso nelle viscere piene di template di una libreria, anche quando è molto competente nel creare applicazioni usando quella libreria. E scrivere una libreria C ++ a destra è un compito di programmazione molto impegnativo, e fatto solo per fornire un ottimo framework a beneficio dello sviluppatore dell'applicazione. Le librerie C ++ non sono semplici internamente, sono (o possono essere ...) potenti ma semplici dal punto di vista dei programmatori di applicazioni.

Ma l'API del kernel non può essere un'API C ++, deve essere un'API indipendente dal linguaggio, quindi la maggior parte delle belle cose in C ++ non sarebbero direttamente utilizzabili su quell'interfaccia. Inoltre, il kernel non è realmente suddiviso in parti di "libreria" e "applicazione" sviluppate in modo indipendente, con un maggiore sforzo logico che va in una libreria, per facilitare la creazione di una massa di applicazioni.

Inoltre, la sicurezza e la stabilità sono più critiche all'interno di un kernel e i metodi virtuali sono molto più dinamici e quindi molto più difficili da isolare e verificare, rispetto ai semplici callback o ad altri meccanismi simili a C.

In breve, sebbene si possa ovviamente scrivere qualsiasi programma C incluso un kernel come C ++, la maggior parte della potenza di C ++ non è ben usata nel kernel. E molti direbbero che gli strumenti di programmazione dovrebbero impedirti di fare cose che non dovresti fare. C ++ no.


+1. Come sviluppatore del kernel la mia "regola empirica" ​​è che se non riesci a stimare facilmente le "righe della cache toccate", la lingua che stai usando sta facendo più male che bene.
Brendan,

Chiarimento: per i kernel si deve presumere che la CPU trascorra la maggior parte del tempo nello spazio utente e che il codice del kernel sia usato sporadicamente (ad es. Quando lo spazio utente chiama l'API del kernel o si verifica un interrupt); il che significa che devi assumere "cold cache". Per le CPU moderne (dove la RAM è lenta rispetto alla velocità della CPU), la cache e gli errori TLB sono costosi, quindi (in combinazione con l'aspettativa della "cache fredda") la metrica "toccate le linee della cache" diventa un indicatore estremamente importante per le prestazioni e / o la scalabilità.
Brendan

5

Bjarne Stroustrup, in un'intervista nel luglio 1999 :

Nessuna di queste lingue era radicalmente diversa o notevolmente migliore di altre lingue contemporanee. Erano, tuttavia, abbastanza buoni e beneficiari di fortuna e fattori sociali


2
Benvenuto David. Quando si cita o si cita, è una buona idea fornire un riferimento (aggiunto!)
Andrew

3

C è un linguaggio di livello molto basso, dal suo design. È a un passo dall'assemblatore; conoscendo il chipset a cui ti rivolgi, potresti, con un po 'di conoscenza, "compilare" manualmente C in ASM. Questo tipo di linguaggio "vicino al metallo" è la chiave per alti livelli di ottimizzazione (per prestazioni, efficienza della memoria, ecc.). Tuttavia, poiché è così vicino al metal, non si ottiene molto gratuitamente con questa lingua; è un linguaggio procedurale, non orientato agli oggetti, e quindi lavorare con tali costrutti comporta un sacco di codice boilerplate per creare e consumare costrutti multi-valore in memoria.

Il C ++ è "C one better", aggiungendo una serie di funzionalità di facile utilizzo come l'allocazione dinamica della memoria, il marshalling della struttura integrata, un'ampia libreria di codice predefinito, ecc., A spese di alcune perdite di efficienza (ancora molto meglio rispetto agli ambienti di runtime gestito). Per il programmatore medio, i vantaggi superano di gran lunga gli svantaggi in aree della base di codice che non necessitano di controllo anale-ritentivo dell'allocazione di memoria ecc.

La combinazione dei due è piuttosto tradizionale; usi C per scrivere le aree più critiche in termini di prestazioni ed efficienza della memoria della base di codice, con cui puoi quindi lavorare in modo più astratto tramite chiamate di metodo dal codice C ++, che può essere organizzato e progettato in modo più elegante rispetto al super performante , codice C ottimamente superbo.


2
Per quanto riguarda l'efficienza, mi ripeterò: (1) La gente del C ++ ti dirà che sono cazzate. (2) Sto dicendo che non vedo motivo per cui questo dovrebbe essere il caso, e vorrei esempi concreti. Non esempi di come sia facile scrivere codice meno efficiente, ma esempi di come essere efficienti come C richiede un'indebita bruttezza.

3
Definire "brutto"; Codifico in C # per vivere, e ogni volta che vedo esempi di codice C ++ in StackOverflow, rabbrividisco a quanta cruft è considerata normale nell'uso quotidiano del linguaggio. Quando ho codificato in C ++ molto tempo fa, ho visto spesso il codice C e ho eseguito il cring; tipi di struttura dell'imballaggio manuale, calcoli del puntatore di esecuzione per salti manuali, ASM incorporato ... yuck. Alcune persone lamentano la perdita di conoscenze di basso livello tra i programmatori Java / .NET; Lo considero un grande vantaggio per la produttività.
Keith

1
Non hai risposto alla mia domanda;) Per "brutto" intendo "brutto per gli standard dei guru del C ++". In altre parole, esempi in cui non è possibile utilizzare "C ++ moderno" ed essere efficienti come C.

2
Potrebbe essere vero (sinceramente non lo so). Per lo sviluppo del kernel (e alcuni altri campi), tuttavia non stiamo parlando di programmatori medi.

3
La gente dimentica che C -> C ++ è un continuum. Troppo spesso, questi argomenti stanno confrontando il C ++ buono e moderno con C. Puoi prendere un programma C e farlo compilare con un compilatore C ++ in un tempo relativamente breve e funzionerà esattamente alla stessa velocità. Se una moderna funzionalità C ++ è "troppo lenta", non utilizzarla. Ciò può anche includere cose del genere iostream. "Troppo lento" non è mai una buona scusa per usare C su C ++.
Gort il robot il

1

Potrebbe essere che con C passi la maggior parte del tuo tempo a pensare al problema in questione e a come codificare la soluzione. In C ++ finisci per pensare al C ++ e alla sua miriade di caratteristiche, funzioni e sintassi oscura.

Anche in molti negozi C ++ il tuo codice viene monitorato dalla "polizia della moda" che è affascinato dall'ultima serie di modelli di design o dalle ultime dichiarazioni incomprensibili del grande dio Stroustrup. Il codice grazioso diventa più apprezzato del codice di lavoro, trovare un uso per l'ultimo set di modelli Boost è ammirato più che trovare una soluzione funzionante per l'azienda.

La mia esperienza è che, per tutte le funzionalità intelligenti e la purezza OO del C ++, la codifica in C semplice consente di eseguire il lavoro in modo più rapido ed efficace.


0

È possibile che le parti C non siano ben trasportabili con il compilatore C ++ utilizzato per le parti C ++. Forse il codice C è scadente con il compilatore C in modi che si interrompono con il compilatore C ++.

Se si dispone di un compilatore C ++ di qualità, non c'è quasi motivo di mescolare C e C ++ in un progetto. Quasi.

L'unico motivo sarebbe che il tuo progetto condivide il codice C con altri progetti, il codice non viene compilato come C ++ e non desideri mantenere un fork C ++ di quel codice.


-1

Penso che tu l'abbia al contrario: il extern "C"blocco garantisce che le convenzioni di chiamata C vengano utilizzate per tutte le funzioni all'interno del blocco. Quindi puoi chiamare funzioni C pure da C ++, non funzioni C ++ da C. Indipendentemente da ciò, immagino che il motivo per cui le persone usano sia C che C ++ è perché molte librerie di basso livello sono scritte usando C, ed è più facile usare qualcosa che esiste già (ed è presumibilmente eseguito il debug e ottimizzato) che scrivere il tuo. OTOH, C ++ offre molte funzioni di alto livello con cui le persone preferiscono lavorare, quindi le usano per il resto.


-2

Esistono vari livelli di piattaforme integrate che usano C come linguaggio di programmazione (ovviamente è la tua libertà di usare il linguaggio assembly in qualsiasi momento)

Per "Livello" sto parlando della SRAM interna e del livello delle risorse ROM per un sistema.

Queste piattaforme a volte sono limitate dalle risorse (ad esempio, alcune piattaforme 8051 hanno solo 128 byte di SRAM utente).

Non ha senso supportare l'allocazione dinamica della memoria con una quantità così piccola di RAM. (nuovo / elimina) o anche malloc in C.

Uno dei principali miglioramenti da C a C ++ è il paradigma orientato agli oggetti. C ++ è adatto per software con un ingombro di memoria maggiore

ma non nel firmware incorporato con limiti di dimensioni fino a 32 KB. (ad es. in una plaform MCU a 16 bit)

Non è necessario disporre di un compilatore C ++ che è generalmente più complicato del compilatore C. (almeno i provider SDK non si preoccuperanno di farlo).

In realtà non riesco a trovare un compilatore C ++ su una piattaforma ARM7 a 32 bit.

Non vale la complessità

In Some 8051 (8 bit): 1 MB di ROM, 128 MB di RAM

TI MSP430 (16 bit): 32 KB ROM, 4 KB RAM

Core CPU CPU Cortex ™ -M3 ARM 32-bit ST Microelectronics (STM32F103T4): 16 o 32 Kbyte di memoria Flash 6 o 10 Kbyte di SRAM


2
Questo non è nulla di nuovo rispetto alle altre risposte già pubblicate qui.
Martijn Pieters,

Un compilatore C ++ a 32 bit per ARM? Se lo desideri, puoi compilare LLVM dal sorgente tu stesso dopo alcune modifiche per ottenere un compilatore C ++ per iOS.
Cole Johnson,

-4

Vedo un paio di possibili motivi:

  • C è un po 'più efficiente rispetto all'equivalente C ++.
  • Alcune librerie che usano sono scritte in C.
  • Usano alcune parti del kernel Linux, che è scritto in C.

Modificato: Come risulta, il terzo argomento non è vero (vedi commenti).


5
(1) La gente del C ++ avrebbe cominciato a differire. E oggettivamente non vedo alcun motivo per cui questo dovrebbe essere il caso. (2) C ++ può chiamare nel codice C bene (questo è il punto di compatibilità con le versioni precedenti e extern "C").

1
Se MS utilizza alcune parti del kernel Linux e il kernel Linux è GPL, ciò non significherebbe che anche Windows dovrebbe essere GPL?
TomJ,

1
@TomJ in realtà è per questo che sono stati costretti a donare un paio di migliaia di linee anche a Linux. + Perché pensi che supportino lo sviluppo di Linux?
Pijusn,

2
@Pius Il suo punto è (ed ha ragione AFAIK), se ci fosse il codice GPL collegato nel kernel di Windows, l'intero kernel dovrebbe essere GPL'd (a condizione che non ci sia un accordo separato con i detentori del copyright).

@delnan, non sono sicuro dei dettagli. Non sono un avvocato, quindi non posso commentarlo. Ma c'è stato un piccolo scandalo un paio di anni fa al riguardo. Non sono sicuro, ma penso che potrei essere stato il modulo di rete di tutte le cose folli.
Pijusn,

-4

Perché C è probabilmente un linguaggio migliore di C ++. E poiché parte del codice è stato scritto prima che il C ++ diventasse popolare e le persone non avevano motivo di sostituirlo.

E poiché C ++ ha molte funzionalità che possono violare il codice se non si presta attenzione quando lo si utilizza in un kernel.


C ++ prevede librerie dinamiche? E cos'è la memoria dinamica?

4
-1 per [stuff] that C++ expects. Perché C ++ utilizza più heap di C? Perché C ++ richiede più dll di C? Semplicemente NON VERO
Thomas Eding,

1
Correzione: si perdono le librerie scritte in C ++. Quindi torna al punto 1 se stai usando C ++ o C. Perché limitarti alla funzionalità C se puoi usare modelli, classi, distruttori, const e ogni sorta di altra bontà.
Thomas Eding,

6
Che cosa? Modelli, eccezioni, oggetti (inclusi costruttori, distruttori, operatori sovraccarichi, ora spostano la costruzione e - praticamente? - tutto il resto), ecc. Funzionano perfettamente indipendentemente da dove sia la memoria (pila, memoria statica, pool personalizzato o altro) . I container standard usano l'allocazione degli heap di default, ma i loro allocatori possono essere personalizzati e i ragazzi del kernel scrivono comunque le proprie raccolte e la gestione della memoria. -1

2
Cordiali saluti: Ho rimosso il mio voto negativo perché non credo che la tua risposta sia attivamente dannosa ormai, ma non la considero particolarmente utile o perspicace.
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.