Perché le persone usano C se è così pericoloso?


132

Sto pensando di imparare C.

Ma perché le persone usano C (o C ++) se può essere usato 'pericolosamente'?

Per pericoloso, intendo con puntatori e altre cose simili.

Come la domanda Stack Overflow Perché la funzione gets è così pericolosa che non dovrebbe essere usata? . Perché i programmatori non usano solo Java o Python o un altro linguaggio compilato come Visual Basic?


152
Perché gli chef usano i coltelli, se possono essere usati 'pericolosamente'?
oerkelens,

78
Con un grande potere viene una grande responsabilità.
Pieter B,

10
Joe Blow, pontificato molto?
Matthew James Briggs,

4
Perché "Back In The Day", quando C divenne il linguaggio della scelta, ci aspettavamo di essere in grado di gestire cose del genere, perché dovevamo. I linguaggi interpretati o codificati in byte erano troppo lenti perché i processori del giorno erano molto più lenti. (Oggi posso acquistare un PC desktop di fascia bassa con una CPU multi-core da 2+ GHz e 4 GB di memoria da Dell per $ 279. Non hai IDEA quanto sia incredibile questo aspetto per un ragazzo come me per il quale un PC a 4 MHz con 640 kilobyte di memoria era felicità ...). Ammettilo: la legge di Moore ha vinto. Gioco. Al di sopra di!
Bob Jarvis,

6
@Bob Jarvis: il gioco non è finito. Se ritieni che il tuo PC da 2 + GHz, 4 GB - o, del resto, il tuo cluster di diverse centinaia di PC da 4 GHz con le ultime GPU CUDA, o qualsiasi altra cosa - sia abbastanza veloce, semplicemente non stai lavorando su problemi abbastanza duri :-)
jamesqf,

Risposte:


246
  1. C precede molte delle altre lingue a cui stai pensando. Molto di ciò che ora sappiamo su come rendere la programmazione "più sicura" deriva dall'esperienza con linguaggi come C.

  2. Molti dei linguaggi più sicuri emersi da quando C fanno affidamento su un runtime più ampio, un set di funzionalità più complicato e / o una macchina virtuale per raggiungere i propri obiettivi. Di conseguenza, C è rimasto una specie di "minimo comune denominatore" tra tutte le lingue popolari / tradizionali.

    • C è un linguaggio molto più semplice da implementare perché è relativamente piccolo e ha maggiori probabilità di funzionare adeguatamente anche nell'ambiente più debole, quindi molti sistemi embedded che hanno bisogno di sviluppare i propri compilatori e altri strumenti hanno maggiori probabilità di essere in grado di fornire un compilatore funzionale per C.

    • Poiché C è così piccolo e così semplice, altri linguaggi di programmazione tendono a comunicare tra loro utilizzando un'API di tipo C. Questo è probabilmente il motivo principale per cui C non morirà mai veramente, anche se la maggior parte di noi interagisce con esso solo tramite involucri.

  3. Molti dei linguaggi "più sicuri" che cercano di migliorare in C e C ++ non stanno cercando di essere "linguaggi di sistema" che ti danno il controllo quasi totale sull'utilizzo della memoria e sul comportamento in fase di esecuzione del tuo programma. Mentre è vero che sempre più applicazioni al giorno d'oggi non hanno bisogno di quel livello di controllo, ci saranno sempre una manciata di casi in cui è necessario (in particolare all'interno delle macchine virtuali e dei browser che implementano tutti questi linguaggi belli e sicuri per il il resto di noi).

    Oggi ci sono alcuni linguaggi di programmazione di sistemi (Rust, Nim, D, ...) che sono più sicuri di C o C ++. Hanno il senno di poi e si rendono conto che la maggior parte delle volte non è necessario un controllo così accurato, quindi offrono un'interfaccia generalmente sicura con alcuni hook / modalità non sicuri a cui è possibile passare quando è veramente necessario.

  4. Anche all'interno di C, abbiamo imparato molte regole e linee guida che tendono a ridurre drasticamente il numero di bug insidiosi che si presentano nella pratica. È generalmente impossibile ottenere lo standard per applicare queste regole in modo retroattivo perché ciò romperebbe troppo il codice esistente, ma è comune usare avvisi del compilatore, linter e altri strumenti di analisi statica per rilevare questo tipo di problemi facilmente prevenibili. Il sottoinsieme di programmi C che passano questi strumenti a pieni voti è già molto più sicuro di "solo C", e qualsiasi programmatore C competente in questi giorni ne utilizzerà alcuni.


Inoltre, non dovrete mai fare un concorso Java offuscato divertente come il contest offuscato C .


7
"minimo comune denominatore" suona denigratorio. Direi che, a differenza delle molte lingue molto più pesanti, C non impone una tonnellata di bagaglio extra che non ti serve e ti dà una base velocissima su cui implementare le cose di cui hai bisogno. È quello che volevi dire?
underscore_d

9
"Non puoi davvero averne uno senza l'altro": in realtà molte nuove lingue (Rust, Nim, D, ...) tentano di farlo. Ciò si riduce sostanzialmente all'abbinamento di un sottoinsieme "sicuro" della lingua con un paio di primitive "non sicure" per quando questo livello di controllo è assolutamente necessario. Tuttavia, tutti si basano sulle conoscenze accumulate da C e C ++, quindi forse si dovrebbe dire che al momento dello sviluppo di C e C ++, non si poteva avere l'uno senza l'altro, e al giorno d'oggi ci sono linguaggi che tentano di partizionare i loro pezzi "non sicuri", ma non hanno ancora raggiunto.
Matthieu M.

6
1) non è un punto valido! C prese le caratteristiche di Algol 68, che in questo senso è un linguaggio "sicuro"; quindi gli autori conoscevano tali lingue. Gli altri punti sono fantastici.
reinierpost,

4
@MatthieuM. Potresti voler guardare anche Microsoft Research. Negli ultimi dieci o due anni hanno prodotto alcuni sistemi operativi gestiti, inclusi alcuni più veloci (completamente casuali - l'obiettivo principale della maggior parte di questi sistemi operativi di ricerca è la sicurezza, non la velocità) rispetto a un sistema operativo equivalente non gestito per determinati carichi di lavoro reali . L'accelerazione è dovuta principalmente ai vincoli di sicurezza: il controllo eseguibile statico e dinamico consente ottimizzazioni non disponibili nel codice non gestito. C'è un bel po 'da guardare, tutto sommato, e le fonti sono incluse;)
Luaan,

3
@Luaan: Midori sembra così fantastico; Non vedo l'ora di ricevere articoli sul blog di Joe.
Matthieu M.,

41

Innanzitutto, C è un linguaggio di programmazione dei sistemi. Ad esempio, se si scrive una macchina virtuale Java o un interprete Python, sarà necessario un linguaggio di programmazione dei sistemi per scriverli.

In secondo luogo, C fornisce prestazioni che linguaggi come Java e Python non offrono. In genere, il calcolo ad alte prestazioni in Java e Python utilizzerà librerie scritte in un linguaggio ad alte prestazioni come C per fare il lavoro pesante.

Terzo, C ha un'impronta molto più piccola rispetto a linguaggi come Java e Python. Questo lo rende utilizzabile per i sistemi embedded, che potrebbero non disporre delle risorse necessarie per supportare gli ambienti di runtime di grandi dimensioni e le esigenze di memoria di linguaggi come Java e Python.


Un "linguaggio di programmazione di sistemi" è un linguaggio adatto a costruire sistemi di forza industriale; così come sono, Java e Python non sono linguaggi di programmazione di sistemi. "Esattamente ciò che rende un linguaggio di programmazione di sistemi" non rientra nell'ambito di questa domanda, ma un linguaggio di programmazione di sistemi deve fornire supporto per lavorare con la piattaforma sottostante.

D'altra parte (in risposta ai commenti), un linguaggio di programmazione di sistemi non deve essere auto-hosting. Questo problema è venuto perché la domanda iniziale chiesto "Perché la gente usa C", il primo commento chiesto "perché si avrebbe bisogno di un linguaggio come C" quando si dispone di PyPy, e ho notato che PyPy fa infatti uso C. Quindi, era originariamente rilevante per la domanda, ma sfortunatamente (e confusamente) "self-hosting" non è in realtà rilevante per questa risposta. Mi dispiace di averlo sollevato.

Quindi, per riassumere: Java e Python non sono adatti alla programmazione di sistemi non perché le loro implementazioni primarie vengono interpretate o perché le implementazioni compilate in modo nativo non sono auto-ospitate, ma perché non forniscono il supporto necessario per lavorare con la piattaforma sottostante.


19
"se scrivi una macchina virtuale Java o un interprete Python, avrai bisogno di un linguaggio di programmazione dei sistemi per scriverli." Uh? Come si spiega PyPy? Perché avresti bisogno di un linguaggio come C per scrivere un compilatore, un interprete o una macchina virtuale?
Vincent Savard,

10
Credo che tu abbia affermato di aver bisogno di un linguaggio di programmazione del sistema per scrivere una macchina virtuale Java o un interprete Python quando hai detto "se scrivi una macchina virtuale Java o un interprete Python, avrai bisogno di un linguaggio di programmazione del sistema per scriverli". Se PyPy non ti soddisfa, puoi anche cercare qualsiasi interprete o compilatore scritto in Haskell. O davvero, basta aggiungere un riferimento a supporto del tuo reclamo.
Vincent Savard,

16
Anche se è completamente tartaruga, qualcosa come PyPy non potrebbe esistere senza un interprete Python scritto in un'altra lingua.
Blrfl,

18
@Birfl Ma non sta dicendo molto. C non avrebbe potuto essere scritto senza un compilatore di assembly e non è possibile scrivere assembly senza hardware che lo implementa.
gardenhead

11
Se PyPy non è un "linguaggio di programmazione dei sistemi" perché un compilatore C è coinvolto da qualche parte, allora C non è un linguaggio di programmazione dei sistemi perché un assemblatore viene utilizzato da qualche parte. In realtà, non è popolare tradurre C in un'altra lingua in questi giorni? es. LLVM

30

Mi dispiace aggiungere un'altra risposta, ma non credo che nessuna delle risposte esistenti riguardi direttamente la tua prima frase affermando:

'Sto pensando di imparare C'

Perché? Vuoi fare il tipo di cose che di solito viene usato per oggi (ad esempio driver di dispositivo, macchine virtuali, motori di gioco, librerie multimediali, sistemi integrati, kernel del sistema operativo)?

Se sì, allora sì, sicuramente impara il C o il C ++ a seconda di chi ti interessa. Vuoi impararlo in modo da avere una comprensione più profonda di ciò che sta facendo il tuo linguaggio di alto livello?

Quindi prosegui citando i problemi di sicurezza. Non hai necessariamente bisogno di una profonda conoscenza della C sicura per fare quest'ultima, nello stesso modo in cui un esempio di codice in un linguaggio di livello superiore potrebbe darti un'idea senza essere pronto per la produzione.

Scrivi del codice C per ottenere l'essenza. Quindi rimettilo sullo scaffale. Non preoccuparti troppo della sicurezza se non vuoi scrivere il codice C di produzione .


2
Ottimo lavoro nel rispondere a quella che sembra essere la vera domanda! Un ottimo modo per apprezzare C / C ++ e linguaggi "più sicuri" per tutto ciò che realmente sono è provare a scrivere qualcosa come un semplice motore di database. Avrai una buona sensazione per ciascuno degli approcci che provi e vedrai dove ti porta. Vedrai ciò che sembra naturale in entrambi e scoprirai dove l'approccio naturale fallisce (ad es. È molto facile "serializzare" i dati grezzi in C - basta scrivere i dati !; ma il risultato non è portatile, quindi può essere di utilità limitata). Comprendere la sicurezza è difficile, perché la maggior parte dei problemi potrebbe essere difficile da affrontare.
Luaan,

1
@Luaan esattamente, imparare a copiare una stringa usando i puntatori ti dà l'idea, imparare a farlo in modo sicuro è un altro livello e, a seconda dei tuoi obiettivi, forse uno non necessario.
Jared Smith,

2
Questa non era davvero la domanda. Ma è stato utile per prendere una decisione. Ho deciso di farlo. Sono disposto a saperne di più sul funzionamento interiore di tutto ciò su cui si basa. E mi piace solo programmare. In questo modo spero di capire meglio il funzionamento interno dei computer. È solo per divertimento.
Tristan,

10
Non sono d'accordo con l'ultima frase. Scopri come farlo subito prima di sviluppare cattive abitudini.
glglgl,

2
@glglgl IDK, se leggo (o scrivo) uno snippet JavaScript sul Web lo faccio con la consapevolezza che non è pronto per la produzione: non avrà una gestione delle eccezioni, potrebbe essere O (n ^ 2), ecc. Nessuno di ciò è necessario per ottenere il punto. Tutto ciò è necessario per il codice di produzione. Perché è diverso? Riesco a scrivere ingenua C per la mia edificazione, comprendendo intellettualmente che se volessi metterlo in circolazione avrei bisogno di fare molto più lavoro.
Jared Smith,

14

Questa è una domanda ENORME con tonnellate di risposte, ma la versione breve è che ogni linguaggio di programmazione è specializzato per situazioni diverse. Ad esempio, JavaScript per il web, C per roba di basso livello, C # per qualsiasi cosa Windows, ecc. Aiuta a sapere cosa vuoi fare una volta che conosci la programmazione per decidere quale linguaggio di programmazione scegliere.

Per affrontare il tuo ultimo punto, perché C / C ++ su Java / Python, spesso arriva alla velocità. Realizzo giochi e Java / C # sta raggiungendo solo di recente velocità sufficientemente buone per il funzionamento dei giochi. Dopotutto, se vuoi che il tuo gioco funzioni a 60 frame al secondo e vuoi che il tuo gioco faccia molto (il rendering è particolarmente costoso), allora hai bisogno che il codice sia eseguito il più velocemente possibile. Python / Java / C # / Molti altri girano su "interpreti", un ulteriore livello di software che gestisce tutte le cose noiose che C / C ++ non gestisce, come la gestione della memoria e della garbage collection. Quel sovraccarico extra rallenta le cose, quindi quasi ogni grande gioco che vedi è stato fatto (negli ultimi 10 anni, comunque) in C o C ++. Ci sono eccezioni: il motore di gioco Unity utilizza C # * e Minecraft utilizza Java, ma sono l'eccezione, non la regola. In generale,

* Anche Unity non è tutto C #, grossi pezzi di esso sono C ++ e tu usi semplicemente C # per il tuo codice di gioco.

MODIFICA Per rispondere ad alcuni dei commenti che sono emersi dopo aver pubblicato questo: Forse stavo semplificando troppo, stavo solo dando un quadro generale. Con la programmazione, la risposta non è mai semplice. Ci sono interpreti per C, Javascript può essere eseguito al di fuori del browser e C # può essere eseguito praticamente su qualsiasi cosa grazie a Mono. Diversi linguaggi di programmazione sono specializzati per domini diversi, ma alcuni programmatori da qualche parte probabilmente hanno capito come far funzionare qualsiasi linguaggio in qualsiasi contesto. Dato che l'OP sembrava non conoscere molta programmazione (supposizione da parte mia, scusate se sbaglio), stavo cercando di mantenere semplice la mia risposta.

Per quanto riguarda i commenti sul fatto che C # sia veloce quasi quanto C ++, la parola chiave è quasi. Quando ero al college, andavamo in tournée in molte compagnie di giochi e il mio insegnante (che ci aveva incoraggiato a spostarci da C # a C ++ per tutto l'anno) chiese ai programmatori di tutte le compagnie che andavamo al perché C ++ su C # e ognuno detto che C # è troppo lento. In generale funziona veloce, ma il Garbage Collector può compromettere le prestazioni perché non puoi controllare quando viene eseguito e ha il diritto di ignorarti se non vuole eseguirlo quando lo consiglia. Se hai bisogno di qualcosa per essere ad alte prestazioni, non vuoi qualcosa di così imprevedibile.

Per rispondere al mio commento "raggiungendo solo le velocità", sì, gran parte degli aumenti di velocità di C # provengono da un hardware migliore, ma poiché il framework .NET e il compilatore C # sono migliorati, ci sono stati alcuni aumenti di velocità.

A proposito del commento "i giochi sono scritti nella stessa lingua del motore", dipende. Alcuni lo sono, ma molti sono scritti in un ibrido di lingue. Unreal può fare UnrealScript e C ++, Unity fa C # Javascript e Boo, molti altri motori scritti in C o C ++ usano Python o Lua come linguaggi di scripting. Non c'è una risposta semplice lì.

E solo perché mi ha infastidito leggere "chi se ne frega se il tuo gioco funziona a 200 fps o 120 fps", se il tuo gioco funziona a una velocità superiore a 60 fps, probabilmente stai sprecando il tempo della CPU, poiché il monitor medio non aggiorna nemmeno quello veloce. Alcuni di fascia più alta e quelli più recenti lo fanno, ma non è standard (ancora ...).

E riguardo all'osservazione "ignorando decenni di tecnologia", sono ancora nei miei primi anni '20, quindi quando sto estrapolando all'indietro, eccomo principalmente a ciò che mi hanno detto programmatori più anziani e più esperti. Ovviamente questo verrà contestato su un sito come questo, ma vale la pena considerare.


4
" C # per qualsiasi Windows " - Oh, è un tale errore. E tu fornisci persino un esempio. Unità. AFAIK Non è scritto, fornisce API C # perché il linguaggio è gradevole e adattabile. È davvero ben progettato. E mi piace di più il c ++, ma il merito dovrebbe essere dato dove è dovuto. Forse hai mescolato C # con .NET? Stanno insieme abbastanza spesso.
luk32,

2
"Anche Unity non è tutto C #, grossi pezzi di esso sono C ++" E? I giochi in Unity spesso usano ampiamente C # e sono in circolazione da un po 'di tempo ormai. Suggerire che C # "sta raggiungendo velocità di recente" ha bisogno di più contesto o corre il rischio di essere cieco alla tecnologia di questi decenni.
NPSF3000,

2
Quasi ogni gioco di grandi dimensioni è stato scritto nella lingua del motore utilizzato: la quantità di lavoro che avrebbe dovuto essere duplicato era così grande che nessun'altra considerazione tecnica valeva la pena prendere in considerazione. Il rendering è davvero costoso, ma al giorno d'oggi è tutto scritto in shader e il linguaggio del circuito logico è irrilevante.
Peter Taylor,

2
C # è sempre stato compilato JIT (a differenza di Java, dove il tuo commento è corretto), ed era abbastanza capace di velocità di esecuzione molto simili a C ++ fin dall'inizio se sapevi cosa stavi facendo. È il 2003, non qualcosa che considererei recente. La velocità pura non è il problema principale per i giochi (specialmente con shader programmabili sulla GPU), ci sono altre cose che hanno reso le lingue come C # più o meno popolari a volte. Due problemi principali sono le API (che sono fortemente orientate alla C e l'interfaccia potrebbe essere costosa) e GC (principalmente per problemi di latenza, non throughput non elaborato).
Luaan,

1
@gbjbaanb Non sono solo le CPU a essere più veloci, ma un grosso problema è che C ++ e C hanno avuto decenni per perfezionare i loro compilatori e il loro runtime, mentre Java è partito sostanzialmente da zero (progettato principalmente come piattaforma multipiattaforma). Con il miglioramento della VM (ad es. Il passaggio da un interprete a un compilatore JIT, un miglioramento di GC ...), migliorarono anche le prestazioni delle applicazioni Java. Gran parte del vantaggio che C / C ++ ha ancora è nell'approccio "speriamo che non si rompa nulla", evitando molti controlli ritenuti "non necessari". Ma è ancora un enorme trambusto della memoria - in effetti, i miglioramenti nell'uso della CPU spesso significano peggiori prestazioni della memoria :)
Luaan

13

È divertente affermare che C non è più sicuro perché "ha puntatori". È vero il contrario: Java e C # hanno praticamente solo puntatori (per tipi non nativi). L'errore più comune in Java è probabilmente l'eccezione del puntatore null (cfr. Https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare ). Il secondo errore più comune è probabilmente quello di contenere riferimenti nascosti ad oggetti inutilizzati (ad es. I dialoghi chiusi non vengono eliminati) che pertanto non possono essere rilasciati, portando a programmi a esecuzione prolungata con un footprint di memoria sempre crescente.

Esistono due meccanismi di base che rendono C # e Java più sicuri e più sicuri in due modi diversi:

  • La garbage collection rende meno probabile che il programma tenti di accedere agli oggetti scartati. Ciò rende meno probabile che il programma si termini in modo imprevisto. A differenza di C, Java e C # di default allocano dinamicamente i dati non nativi. Ciò rende la logica del programma in realtà più complessa, ma la garbage collection integrata, a un costo, prende il sopravvento.

I puntatori intelligenti recenti di C ++ rendono questo lavoro più facile per i programmatori.

  • Java e C # vengono compilati in un codice intermedio che viene interpretato / eseguito da un tempo di esecuzione elaborato. Ciò aggiunge un livello di sicurezza poiché il tempo di esecuzione può rilevare attività illecite di un programma. Anche se il programma è codificato in modo non sicuro (il che è possibile in entrambe le lingue), il rispettivo tempo di esecuzione in teoria impedisce di "irrompere" nel sistema.
    Il tempo di esecuzione non protegge, ad esempio, dai tentativi di sovraccarico del buffer, ma in teoria non consente exploit di tali programmi. Con C e C ++, al contrario, il programmatore deve programmare in modo sicuro per evitare exploit. Questo di solito non viene raggiunto immediatamente ma necessita di recensioni e iterazioni.

Vale la pena notare, tuttavia, che il tempo di esecuzione elaborato è anche un rischio per la sicurezza. Mi sembra che Oracle aggiorni la JVM ogni paio di settimane a causa di problemi di sicurezza appena scoperti. Naturalmente, è molto più difficile verificare la JVM rispetto a un singolo programma.

La sicurezza di un tempo di esecuzione elaborato è quindi ambigua e in parte ingannevole: il tuo programma C medio può, con revisioni e iterazioni, essere reso ragionevolmente sicuro. Il tuo programma Java medio è sicuro solo come JVM; cioè, non proprio. Mai.

L'articolo su gets()cui ti colleghi riflette le decisioni della biblioteca storica che verrebbero prese diversamente oggi, non il linguaggio principale.


3
Penso che il punto dell'autore originale sia che in C sei in grado di eseguire azioni non controllate su questi puntatori. In java, ottieni subito una bella eccezione: in C potresti non capire che stai leggendo una posizione non valida fino a quando lo stato della tua applicazione non è danneggiato.
Sam Dufel,

1
Inoltre, stackoverflow.com/questions/57483/… - sarebbe più preciso affermare che java ha "praticamente solo riferimenti".
Sam Dufel,

4
Ho visto tutti i tipi di bug interessanti derivanti dai tentativi di evitare puntatori espliciti. Di solito il problema fondamentale è la confusione tra copia e riferimento. In C, se ti passo un puntatore a qualcosa, sai che modificarlo influirà sull'originale. Alcuni dei tentativi di evitare gli indicatori offuscano questa distinzione, portando a un labirinto di copie profonde, copie superficiali e confusione generale.
Arlie Stephens,

Asserire che la JVM di Oracle fa schifo (dal punto di vista dell'emorragia delle vulnerabilità di sicurezza sfruttabili) e quindi i tempi di esecuzione delle lingue gestite in generale introducono più preoccupazioni di sicurezza rispetto all'uso di una lingua gestita, è come dire che Adobe Flash è orribile come fonte di insicurezza e programma che la riproduzione di video e animazioni da un sito Web deve essere intrinsecamente ridicolmente insicura. Non tutti i runtime Java sono quasi uguali a quelli dell'abominio JVM vintage di Oracle / Sun degli anni '90, e non tutti i linguaggi gestiti sono Java. (Beh, ovviamente.)
informato il

@halfinformed Well; Stavo dicendo che un programma è sicuro tanto quanto il suo runtime e che il programma "medio" (leggi: piccolo) può essere reso con uno sforzo più sicuro di qualsiasi runtime di grandi dimensioni come un interprete di codici byte. Questa affermazione sembra innegabile. Il fatto che un particolare programma autonomo o un determinato runtime sia più o meno sicuro dell'altro dipende dalla rispettiva complessità e dal design, dalla codifica e dalla qualità di manutenzione. Ad esempio, non direi che sendmail sia più sicuro della Java VM di Oracle; ma qmail potrebbe essere.
Peter A. Schneider,

10

Poiché la "sicurezza" costa velocità, le lingue "più sicure" funzionano a una velocità inferiore.

Ti chiedi perché usare un linguaggio "pericoloso" come C o C ++, qualcuno ti scriva un driver video o simili in Python o Java, ecc. E vedi come ti senti sulla "sicurezza" :)

Scherzi a parte, devi essere il più vicino possibile alla memoria principale della macchina per poter manipolare pixel, registri, ecc ... Java o Python non possono farlo con nessun tipo di velocità degna di prestazioni ... C e C ++ entrambi ti permettono di farlo attraverso puntatori e simili ...


20
Non è vero in generale che la sicurezza costa velocità . Le lingue più sicure disponibili eseguono la maggior parte dei controlli al momento della compilazione. O'Caml, Ada, Haskell, Rust non si muovono molto indietro rispetto a C in termini di velocità media di runtime. Quello che fanno di solito è un notevole sovraccarico di dimensioni del programma, efficienza della memoria, latenza e ovviamente tempo di compilazione. E, sì, hanno difficoltà con roba simile al metallo. Ma questo non è davvero un problema di velocità.
lasciato circa l'

6
Inoltre, C non fa quello che pensi che faccia. C è una macchina astratta . Non ti dà accesso diretto a nulla - questa è una buona cosa. Non puoi nemmeno guardare l'assemblaggio moderno per vedere quanto C ti nasconde: l'assemblaggio moderno (ad es. TASM) sarebbe stato considerato un linguaggio di alto livello quando C era stato sviluppato. Sarei molto felice se qualcuno scrivesse driver in un linguaggio "sicuro", grazie - ciò contribuirebbe a evitare un sacco di quei BSOD e blocchi, per non parlare delle falle di sicurezza :) E, soprattutto, ci sono linguaggi di sistema che sono molto più sicuri di C.
Luaan,

3
@Wintermute Volete davvero cercare Rust prima di fare commenti su come le funzionalità di sicurezza costano necessariamente velocità. Inferno, il sistema di tipo a basso livello di C in realtà inibisce molte utilissime ottimizzazioni che altrimenti i compilatori potrebbero fare (in particolare se si considera che praticamente nessun grande progetto c riesce a evitare di non violare alias rigoroso da qualche parte ).
Voo

7
@Wintermute Sì, il mito secondo cui non è possibile rendere il C / C ++ più sicuro senza introdurre un sovraccarico di prestazioni è molto persistente, motivo per cui lo prendo piuttosto sul serio (ci sono alcune aree in cui questo è certamente vero [controllo dei limiti]). Ora, perché Rust non è più diffuso? Storia e complessità. Rust è ancora relativamente nuovo e molti dei più grandi sistemi scritti in C esistevano prima che Rust fosse mai inventato - non riscriverai un milione di LOC in una nuova lingua anche se fosse molto più sicuro. Inoltre ogni programmatore e il loro cane conoscono C, Rust? Buona fortuna a trovare abbastanza persone.
Voo

3
@Voo Dogs che fa C? ... non c'è da meravigliarsi che abbia visto così tanto codice errato là fuori ... j / k Punto preso su Rust (l'ho appena scaricato e installato, quindi potresti avere un altro convertitore da aggiungere) BTW per quanto riguarda a Rust facendo bene ... Potrei fare lo stesso aumento per "D" :)
Wintermut3

9

Oltre a tutto quanto sopra, esiste anche un caso d'uso piuttosto comune, che utilizza C come libreria comune per altre lingue.

Fondamentalmente, quasi tutte le lingue hanno un'interfaccia API per C.

Esempio semplice, prova a creare un'applicazione comune per Linux / IOS / Android / Windows. Oltre a tutti gli strumenti disponibili, quello che abbiamo finito è stato fare una libreria di base in C, e quindi cambiare la GUI per ciascun ambiente, ovvero:

  • IOS: ObjectiveC può utilizzare le librerie C in modo nativo
  • Android: Java + JNI
  • Linux / Windows / MacOS: con GTK / .Net è possibile utilizzare librerie native. Se usi Python, Perl, Ruby ognuno di essi ha interfacce API native. (Java di nuovo con JNI).

I miei due centesimi,


Uno dei motivi che amo usare, diciamo, PHP, è perché quasi tutte le sue librerie sono, in effetti, scritte in C - per fortuna, o PHP sarebbe insopportabilmente lento :) PHP è fantastico scrivere codice sciatto senza il timore di fare qualcosa di "pericoloso" (ed è per questo che tendo a scrivere molto più codice PHP di ogni altra cosa - mi piace il codice sciatto!: D), ma è bello sapere che sotto molte di queste chiamate di funzioni ci sono i buoni ol 'fidati Librerie C per aumentarne le prestazioni ;-) Al contrario, scrivere codice sciatto in C è un grande no-no ...
Gwyneth Llewelyn,

7

Una difficoltà fondamentale con C è che il nome è usato per descrivere un numero di dialetti con sintassi identica ma semantica molto diversa. Alcuni dialetti sono molto più sicuri di altri.

In C, come originariamente progettato da Dennis Ritchie, le dichiarazioni C sarebbero generalmente mappate alle istruzioni della macchina in modo prevedibile. Poiché C poteva funzionare su processori che si comportavano diversamente quando si verificavano cose come overflow aritmetico firmato, un programmatore che non sapeva come si sarebbe comportata una macchina in caso di overflow aritmetico non sapeva neanche quale codice C in esecuzione su quella macchina si sarebbe comportato, ma se si sapesse che una macchina si comporta in un certo modo (ad es. avvolgente silenzioso complemento a due), le implementazioni su quella macchina in genere farebbero altrettanto. Uno dei motivi per cui C si è guadagnata la reputazione di essere veloce è che nei casi in cui i programmatori sapevano che il comportamento naturale di una piattaforma negli scenari limite si adattava alle loro esigenze, non era necessario che il programmatore o il compilatore scrivessero codice per generare tali scenari .

Sfortunatamente, gli autori di compilatori hanno ritenuto che dal momento che lo Standard non impone requisiti su ciò che le implementazioni devono fare in questi casi (lassismo che era destinato a consentire implementazioni hardware che potrebbero non comportarsi in modo prevedibile), i compilatori dovrebbero sentirsi liberi di generare codice che nega le leggi di tempo e causalità.

Considera qualcosa come:

int hey(int x)
{
   printf("%d", x);
   return x*10000;
}
void wow(int x)
{
  if (x < 1000000)
    printf("QUACK!");
  hey(x);    
}

La teoria del compilatore iper-moderno (ma alla moda) suggerirebbe che il compilatore dovrebbe produrre "QUACK!" incondizionatamente, poiché in ogni caso in cui la condizione era falsa il programma finirebbe per invocare un comportamento indefinito eseguendo un moltiplicazione il cui risultato sarebbe comunque stato ignorato. Poiché lo standard consentirebbe a un compilatore di fare tutto ciò che gli piace in questo caso, consente al compilatore di produrre "QUACK!".

Mentre C era più sicuro del linguaggio assembly, quando si usano compilatori iper-moderni è vero il contrario. Nel linguaggio assembly, l'overflow dei numeri interi può causare un calcolo che porta a risultati insignificanti, ma sulla maggior parte delle piattaforme sarà l'estensione dei suoi effetti. Se i risultati finiscono comunque per essere ignorati, l'overflow non avrà importanza. Nella C ipermoderna, tuttavia, anche quelle che normalmente sarebbero forme "benigne" di comportamento indefinito (come un overflow di numeri interi in un calcolo che finisce per essere ignorato) possono causare l'esecuzione arbitraria del programma.


1
anche in un compilatore iper-moderno, C non limita il controllo sugli array. se lo facesse, ciò non sarebbe compatibile con la definizione della lingua. Uso questo fatto a volte per creare array con un puntatore aggiuntivo al centro dell'array per avere indici negativi.
robert bristow-johnson,

1
Mi piacerebbe vedere le prove del tuo esempio producendo "QUACK!" incondizionatamente. x sicuramente può essere maggiore di 1000000 nel punto di confronto e una successiva valutazione che comporterebbe un overflow non lo impedisce. Inoltre, se hai abilitato l'allineamento che consente di rimuovere il moltiplicatore di overflow, la tua argomentazione sulle restrizioni di intervallo implicite non regge.
Graham,

2
@ robertbristow-johnson: In realtà, lo Standard dice esplicitamente che, dato ad esempio int arr[5][[5], un tentativo di accesso arr[0][5]produrrà un comportamento indefinito. Tale regola rende possibile per un compilatore a cui viene dato qualcosa di simile arr[1][0]=3; arr[0][i]=6; arr[1][0]++;a inferire che arr[1][0]sarà uguale a 4, senza riguardo per il valore di i.
supercat

2
@ robertbristow-johnson: anche se il compilatore alloca array all'interno di una struttura in sequenza senza spazi vuoti, ciò non garantisce che l'indicizzazione di uno degli array abbia effetti su un altro. Vedi godbolt.org/g/Avt3KW per un esempio di come gcc tratterà tale codice.
supercat

1
@ robertbristow-johnson: ho commentato l'assemblea per spiegare cosa sta facendo. Il compilatore vede che il codice memorizza 1 in s-> arr2 [0] e quindi incrementa s-> arr2 [0], quindi gcc combina queste due operazioni facendo in modo che il codice memorizzi semplicemente il valore 2, senza considerare la possibilità che la scrittura interveniente a s-> arr1 [i] potrebbe influenzare il valore di s-> arr1 [0] (poiché, secondo lo standard, non può).
supercat

5

Ragioni storiche. Spesso non riesco a scrivere codice nuovo di zecca, per lo più riesco a mantenere ed estendere le vecchie cose che funzionano da decenni. Sono solo felice che sia C e non Fortran.

Posso essere irritato quando uno studente dice "ma perché mai fai questa terribile X quando potresti fare Y?". Bene, X è il lavoro che ho e paga molto bene le bollette. Ho fatto Y in occasione, ed è stato divertente, ma X è ciò che la maggior parte di noi fa.


5

Cosa è "pericoloso"?

L'affermazione che C è "pericoloso" è un punto di discussione frequente nelle guerre di fiamma di linguaggio (il più delle volte rispetto a Java). Tuttavia, le prove per questa affermazione non sono chiare.

C è un linguaggio con un particolare set di funzionalità. Alcune di queste funzionalità possono consentire alcuni tipi di errori che non sono consentiti da altri tipi di lingue (il rischio della gestione della memoria di C è in genere evidenziato). Tuttavia, questo non è lo stesso di un argomento secondo cui C è più pericoloso di altre lingue in generale . Non sono a conoscenza di nessuno che fornisca prove convincenti su questo punto.

Inoltre, "pericoloso" dipende dal contesto: cosa stai cercando di fare e di quali tipi di rischi sei preoccupato?

In molti contesti considererei il C più "pericoloso" di un linguaggio di alto livello, poiché richiede di eseguire un'implementazione manuale delle funzionalità di base, aumentando il rischio di bug. Ad esempio, fare un po 'di elaborazione di base del testo o sviluppare un sito Web in C di solito sarebbe stupido, perché altre lingue hanno caratteristiche che lo rendono molto più semplice.

Tuttavia, C e C ++ sono ampiamente utilizzati per i sistemi mission-critical, perché un linguaggio più piccolo con un controllo più diretto del duro è considerato "più sicuro" in quel contesto. Da un'ottima risposta Stack Overflow :

Sebbene C e C ++ non siano stati progettati appositamente per questo tipo di applicazione, sono ampiamente utilizzati per software embedded e critici per la sicurezza per diversi motivi. Le principali proprietà della nota sono il controllo sulla gestione della memoria (che consente di evitare la necessità di eseguire la garbage collection, ad esempio), librerie di runtime di base semplici e ben debug e supporto per strumenti maturi. Molte delle catene di strumenti di sviluppo embedded in uso oggi sono state sviluppate per la prima volta negli anni '80 e '90, quando questa era la tecnologia attuale e provengono dalla cultura Unix che era prevalente in quel momento, quindi questi strumenti rimangono popolari per questo tipo di lavoro.

Mentre il codice di gestione della memoria manuale deve essere attentamente controllato per evitare errori, consente un certo controllo sui tempi di risposta dell'applicazione che non è disponibile con le lingue che dipendono dalla garbage collection. Le librerie di runtime principali dei linguaggi C e C ++ sono relativamente semplici, mature e ben comprese, quindi sono tra le piattaforme più stabili disponibili.


2
Direi che l'ipermoderna C è anche più pericolosa del linguaggio assembly o di autentici dialetti di basso livello di C che si comportano in modo coerente come se traducessero coerentemente operazioni C in operazioni di codice macchina senza tener conto dei casi limite in cui le operazioni di codice macchina naturale sarebbero hanno un comportamento definito ma lo standard C non impone requisiti. L'approccio ipermoderno in cui un overflow di numeri interi può negare le regole del tempo e della causalità sembra molto meno suscettibile alla generazione di codice sicuro.
supercat

5

Per aggiungere alle risposte esistenti, va bene dire che sceglierai Python o PHP per il tuo progetto, a causa della loro relativa sicurezza. Ma qualcuno deve implementare quelle lingue e, quando lo fanno, probabilmente lo faranno in C. (O, beh, qualcosa del genere.)

Ecco perché le persone usano C - per creare gli strumenti meno pericolosi che si desidera utilizzare.


2

Consentimi di riformulare la tua domanda:

Sto prendendo in considerazione l'apprendimento [strumento].

Ma perché le persone usano [strumento] (o [strumento correlato]) se [possono] essere usati 'pericolosamente'?

Qualsiasi strumento interessante può essere usato pericolosamente, compresi i linguaggi di programmazione. Si impara di più in modo da poter fare di più (e in modo che meno il pericolo si crea quando si utilizza lo strumento). In particolare, impari lo strumento in modo da poter fare ciò per cui lo strumento è utile (e forse riconoscere quando quello strumento è lo strumento migliore degli strumenti che conosci).

Ad esempio, se è necessario inserire un foro cilindrico di 6 mm di diametro, 5 cm di profondità in un blocco di legno, un trapano è uno strumento molto migliore di un parser LALR. Se sai quali sono questi due strumenti, sai qual è lo strumento giusto. Se sai già come usare un trapano, voilà !, buco.

C è solo un altro strumento. È meglio per alcuni compiti che per altri. Le altre risposte qui affrontano questo. Se impari un po 'di C, arriverai a riconoscere quando è lo strumento giusto e quando non lo è.


Questa risposta è il motivo per cui le domande vengono respinte come "principalmente basate sull'opinione". Non dire che C ha i suoi vantaggi, dì quello che sono!
reinierpost,

1

Sto pensando di imparare C

Non esiste un motivo specifico per non imparare il C ma suggerirei C ++. Offre molto di ciò che fa C (dato che C ++ è un super set di C), con una grande quantità di "extra". L'apprendimento del C prima del C ++ non è necessario: sono effettivamente lingue separate.

In altre parole, se C fosse un insieme di strumenti per la lavorazione del legno, sarebbe probabilmente:

  • martello
  • Chiodi
  • Sega a mano
  • trapano a mano
  • levigatrice a blocchi
  • scalpello (forse)

Puoi costruire qualsiasi cosa con questi strumenti, ma qualcosa di bello richiede potenzialmente molto tempo e abilità.

C ++ è la raccolta di elettroutensili nel tuo negozio di ferramenta locale.

Se ti attieni alle funzionalità di base del linguaggio per iniziare, C ++ ha una curva di apprendimento aggiuntiva relativamente piccola.

Ma perché le persone usano C (o C ++) se può essere usato 'pericolosamente'?

Perché alcune persone non vogliono mobili di IKEA. =)

Scherzi a parte, sebbene molti linguaggi "più alti" di C o C ++ possano avere elementi che li rendono (potenzialmente) "più facili" da utilizzare in determinati aspetti, questa non è sempre una buona cosa. Se non ti piace il modo in cui qualcosa viene fatto o non viene fornita una funzione, probabilmente non c'è molto che puoi fare al riguardo. D'altra parte, C e C ++ forniscono sufficienti funzionalità di linguaggio "di basso livello" (inclusi i puntatori) che è possibile accedere a molte cose in modo abbastanza diretto (specialmente hardware o OS) o costruirlo da soli, cosa che potrebbe non essere possibile in altri lingue implementate.

Più specificamente, C ha il seguente set di funzionalità che lo rendono desiderabile per molti programmatori:

  • Velocità : grazie alla sua relativa semplicità e ottimizzazioni del compilatore nel corso degli anni, è nativamente molto veloce. Inoltre, molte persone hanno capito molte scorciatoie per obiettivi specifici quando si utilizza la lingua, il che rende potenzialmente ancora più veloce.
  • Dimensioni : per motivi simili a quelli elencati per la velocità, i programmi C possono essere ridotti (sia in termini di dimensioni eseguibili che di utilizzo della memoria), il che è auspicabile per ambienti con memoria limitata (ad esempio, incorporati o mobili).
  • Compatibilità - C è in circolazione da molto tempo e tutti hanno strumenti e librerie per questo. Il linguaggio stesso non è nemmeno schizzinoso: si aspetta che un processore esegua istruzioni e memoria per contenere roba e questo è tutto.

    Inoltre, esiste qualcosa noto come Application Binary Interface (ABI) . In breve, è un modo per i programmi di comunicare a livello di codice macchina, che può avere vantaggi rispetto a un'API (Application Programming Interface) . Mentre altri linguaggi come C ++ possono avere un ABI, in genere questi sono meno uniformi (concordati) rispetto a quelli di C, quindi C crea un buon linguaggio di base quando si desidera utilizzare un ABI per comunicare con un altro programma per qualche motivo.

Perché i programmatori non usano solo Java o Python o un altro linguaggio compilato come Visual Basic?

Efficienza (e occasionalmente schemi di gestione della memoria che non possono essere implementati senza un accesso relativamente diretto alla memoria).

L'accesso diretto alla memoria con i puntatori introduce molti trucchi (di solito rapidi) quando puoi mettere le tue zampe sporche sui piccoli e gli zeri nei tuoi cubbyhole di memoria direttamente e non dover aspettare che quel vecchio insegnante distribuisca i giocattoli solo durante la ricreazione, poi raccoglili di nuovo.

In breve, l'aggiunta di elementi potenzialmente crea ritardi o introduce in altro modo complessità indesiderate.

Per quanto riguarda le lingue con script e simili, è necessario lavorare sodo per ottenere lingue che richiedono programmi secondari per funzionare in modo efficiente come C (o qualsiasi linguaggio compilato) in modo nativo. L'aggiunta di un interprete al volo introduce intrinsecamente la possibilità di ridurre la velocità di esecuzione e aumentare l'utilizzo della memoria perché si sta aggiungendo un altro programma al mix. L'efficienza dei tuoi programmi si basa tanto sull'efficienza di questo programma secondario quanto quanto (male =)) hai scritto il codice del programma originale. Per non parlare del fatto che il tuo programma spesso dipende completamente dal secondo programma da eseguire. Quel secondo programma non esiste per qualche motivo su un particolare sistema? Codice no go.

In effetti, l'introduzione di qualcosa di "extra" potenzialmente rallenta o complica il codice. Nei linguaggi "senza puntatori spaventosi", stai sempre aspettando che altri bit di codice vengano ripuliti dietro di te o altrimenti trovi modi "sicuri" per fare le cose - perché il tuo programma sta ancora facendo le stesse operazioni di accesso alla memoria che si potrebbero fare con puntatori. Semplicemente non sei quello che lo gestisce (quindi non puoi farselo, genio = P).

Per pericoloso, intendo con puntatori e altre cose simili. [...] Come la domanda Stack Overflow Perché la funzione gets è così pericolosa che non dovrebbe essere usata?

Per la risposta accettata:

"È rimasta una parte ufficiale della lingua fino allo standard ISO C del 1999, ma è stata ufficialmente rimossa dallo standard del 2011. La maggior parte delle implementazioni C lo supporta ancora, ma almeno gcc emette un avviso per qualsiasi codice che lo utilizza."

L'idea che, poiché qualcosa può essere fatto in una lingua, deve essere fatta è sciocca. Le lingue hanno dei difetti che vengono corretti. Per motivi di compatibilità con codice precedente, questo costrutto può ancora essere utilizzato. Ma non c'è nulla (probabilmente) che costringe un programmatore a usare get () e, in effetti, questo comando è stato sostanzialmente sostituito con alternative più sicure.

Più precisamente, il problema con gets () non è di per sé un puntatore . È un problema con un comando che non sa necessariamente come usare la memoria in modo sicuro. In senso astratto, si tratta di tutti i problemi dei puntatori: leggere e scrivere cose che non dovresti. Questo non è un problema con i puntatori; è un problema con l'implementazione del puntatore.

Per chiarire, i puntatori non sono pericolosi finché non si accede accidentalmente a una posizione di memoria che non si intendeva. E anche allora ciò non garantisce che il tuo computer si scioglierà o esploderà. Nella maggior parte dei casi, il programma smetterà di funzionare (correttamente).

Detto questo, poiché i puntatori forniscono l'accesso alle posizioni di memoria e poiché i dati e il codice eseguibile esistono nella memoria insieme, esiste un rischio reale di corruzione accidentale che si desidera gestire correttamente la memoria.

A quel punto, poiché le operazioni di accesso alla memoria veramente dirette spesso offrono meno benefici in generale di quanto avrebbero potuto fare anni fa, anche i linguaggi raccolti senza immondizia come il C ++ hanno introdotto elementi come i puntatori intelligenti per aiutare a colmare il divario tra efficienza della memoria e sicurezza.

In sintesi, ci sono pochissime ragioni per temere il puntatore purché sia ​​usato in modo sicuro. Basta prendere un suggerimento dalla versione di South Park di Steve "The Crocodile Hunter" Irwin - non andare in giro a infilare il pollice nei buchi di crocs .


2
Non sono d'accordo con il suggerimento di imparare C ++ invece di C. Scrivere bene C ++ è più difficile che scrivere bene C e leggere C ++ è molto più difficile che leggere C. Quindi la curva di apprendimento di C ++ è molto più ripida. "C ++ è un super set di C" Questo è più o meno come dire che gli stivali sono un superset di pantofole. Hanno vantaggi e utilizzo diversi e ognuno ha caratteristiche che l'altro non ha.
martinkunev,

"Scrivere un buon C ++ è più difficile che scrivere un buon C" - Assolutamente. =) "[R] la lettura di C ++ è molto più difficile della lettura di C" - Qualsiasi programmazione avanzata è probabilmente indistinguibile dalla magia ;-) I miei due centesimi sono che questo è molto più programmatore dipendente che dipendente dalla lingua, sebbene C ++ non faccia molto per aiutare se stesso in questa categoria. "Quindi la curva di apprendimento del C ++ è molto più ripida." - A lungo termine, sì. A breve termine, meno (la mia opinione). Aneddoticamente, la maggior parte dei corsi di lingua di base in C e C ++ probabilmente coprono più o meno gli stessi tipi generali di materiale, ad eccezione delle lezioni per C ++.
Anaksunaman,

2
"Hanno vantaggi e utilizzo diversi e ognuno ha caratteristiche che l'altro non ha." - Come accennato "Non esiste un motivo specifico per non imparare C [.]" C è un bel linguaggio e mi attengo a questo. Se è adatto a OP o a chiunque altro, sostengo pienamente l'apprendimento. =)
Anaksunaman l'

L'apprendimento C ti insegna come funziona la macchina (non fino in fondo, ma comunque un passo avanti verso il metallo). Questa è un'ottima ragione per impararlo.
Agent_L

1

Come sempre, il linguaggio di programmazione è solo una conseguenza della risoluzione dei problemi. Dovresti infatti imparare non solo C ma molti linguaggi diversi (e altri modi di programmare un computer, siano essi strumenti della GUI o interpreti di comandi) per avere una cassetta degli attrezzi decente da usare per risolvere i problemi.

A volte scoprirai che un problema si presta bene a qualcosa che è incluso nelle librerie predefinite Java, in tal caso puoi scegliere Java per sfruttarlo. In altri casi potrebbe essere necessario eseguire qualcosa su Windows molto più semplice nel runtime .NET, quindi è possibile utilizzare C # o VB. Potrebbe esserci uno strumento grafico o uno script di comandi che risolve il tuo problema, quindi puoi usarli. Forse devi scrivere un'applicazione GUI su più piattaforme, Java potrebbe essere un'opzione, date le librerie incluse nel JDK, ma, di nuovo, una piattaforma di destinazione potrebbe non avere un JRE, quindi forse scegli invece C e SDL (o simili).

C ha una posizione importante in questo set di strumenti, in quanto è generale, piccolo e veloce e compila anche in codice macchina. È inoltre supportato su ogni piattaforma sotto il sole (non senza ricompilazione comunque).

In conclusione, dovresti imparare quanti più strumenti, lingue e paradigmi possibile.

Allontanati dalla mentalità: "Sono un programmatore X" (X = C, C ++, Java, ecc.)

Usa "Sono un programmatore".

Un programmatore risolve i problemi e progetta algoritmi dando istruzioni alle macchine per eseguire il carico di lavoro. Fine della storia. Questo è irrilevante per la lingua. La tua abilità più importante è la risoluzione dei problemi e la scomposizione logica dei problemi strutturati, l'abilità / scelta del linguaggio è SEMPRE secondaria e / o una conseguenza della natura del problema.

Un percorso interessante se sei interessato a C è quello di estendere il tuo skillset con Go. Go è davvero un C migliorato, con garbage collection e interfacce, oltre a un bel modello / canali di threading incorporato, che porta anche molti dei vantaggi di C (come l'aritmetica del puntatore e la compilazione nel codice macchina).


0

Dipende da cosa intendi farci. C è stato progettato come sostituto del linguaggio assembly ed è il linguaggio di alto livello più vicino al linguaggio macchina. Pertanto ha bassi costi generali in termini di dimensioni e prestazioni ed è adatto per la programmazione di sistemi e altre attività che richiedono un ingombro ridotto e si avvicinano all'hardware sottostante.


0

Quando si lavora a livello di bit e byte, di memoria come raccolta di dati grezzi e omogenei, come spesso sarebbe richiesto per implementare in modo efficace gli allocatori e le strutture di dati più efficienti, non c'è sicurezza. La sicurezza è principalmente un forte concetto relativo al tipo di dati e un allocatore di memoria non funziona con i tipi di dati. Funziona con bit e byte per raggrupparsi con quegli stessi bit e byte che rappresentano potenzialmente un tipo di dati un momento e un altro in seguito.

Non importa se usi C ++ in quel caso. Spargeresti comunque static_castssu tutto il codice per trasmettere da void*puntatori e lavoreresti ancora con bit e byte e ti occuperesti solo di più problemi legati al rispetto del sistema di tipi in questo contesto rispetto a C che ha un sistema di tipi molto più semplice in cui sei libero a memcpybit e byte in giro senza preoccuparsi di bulldozing sul sistema di tipi.

In effetti, spesso è più difficile lavorare in C ++, un linguaggio complessivamente più sicuro, in contesti di così basso livello di bit e byte senza scrivere codice ancora più pericoloso di quanto si farebbe in C, dal momento che si potrebbe abbattere il sistema di tipi di C ++ e fare cose come sovrascrivendo vptrs e non riuscendo a invocare costruttori e distruttori di copie nei momenti appropriati. Se ti prendi il tempo giusto per rispettare questi tipi e usi il posizionamento di nuovi e invoca manualmente i dottori e così via, ti esponi al mondo della gestione delle eccezioni in un contesto troppo basso perché RAII sia pratico e raggiunga l'eccezione- la sicurezza in un contesto di così basso livello è molto difficile (bisogna far finta che qualsiasi funzione possa lanciare e cogliere tutte le possibilità e ripristinare qualsiasi effetto collaterale come transazione indivisibile come se nulla fosse accaduto). Il codice C può spesso "

E sarebbe impossibile implementare tali allocatori in lingue che non ti permettono di diventare "pericoloso" qui; dovresti appoggiarti a qualsiasi allocatore che forniscono (implementato molto probabilmente in C o C ++) e sperare che sia abbastanza buono per i tuoi scopi. E ci sono quasi sempre allocatori e strutture di dati più generali ma meno generici adatti ai tuoi scopi specifici ma molto più strettamente applicabili poiché sono specificamente su misura per i tuoi scopi.

La maggior parte delle persone non ha bisogno di artisti del calibro di C o C ++ poiché può semplicemente chiamare il codice originariamente implementato in C o C ++ o eventualmente anche un assembly già implementato per loro. Molti potrebbero trarre vantaggio dall'innovazione di alto livello, come mettere insieme un programma di immagini che utilizza solo librerie di funzioni di elaborazione delle immagini esistenti già implementate in C, dove non stanno innovando così tanto al livello più basso di loop attraverso singoli pixel, ma forse offrendo un'interfaccia utente molto intuitiva e un flusso di lavoro mai visto prima. In tal caso, se lo scopo del software è solo quello di effettuare chiamate di alto livello in librerie di basso livello ( "elabora l'intera immagine per me, non per ogni pixel, fai qualcosa" ), allora potrebbe essere probabilmente un'ottimizzazione prematura persino tentare di iniziare a scrivere una simile domanda in C.

Ma se stai facendo qualcosa di nuovo a basso livello in cui aiuta ad accedere ai dati in un modo di basso livello come un nuovissimo filtro di immagine mai visto prima che sia abbastanza veloce da funzionare su video HD in tempo reale, allora devi generalmente ottenere un po 'pericoloso.

È facile dare queste cose per scontate. Ricordo un post di Facebook con qualcuno che sottolineava come fosse possibile creare un videogioco 3D con Python con l'implicazione che le lingue di basso livello stanno diventando obsolete, ed era certamente un gioco dall'aspetto decente. Ma Python stava effettuando chiamate di alto livello in librerie implementate in C per fare tutto il lavoro pesante. Non è possibile effettuare Unreal Engine 4 semplicemente effettuando chiamate di alto livello in librerie esistenti. Unreal Engine 4 èla Biblioteca. Ha fatto tutti i tipi di cose che non sono mai esistite in altre librerie e motori dall'illuminazione fino al suo sistema nodale di progetto e come può compilare ed eseguire il codice al volo. Se vuoi innovare a un livello di motore / core / kernel basso, devi ottenere un livello basso. Se tutti gli sviluppatori di giochi passassero a linguaggi sicuri di alto livello, non ci sarebbe Unreal Engine 5, o 6, o 7. Probabilmente ci sarebbero persone che usano ancora Unreal Engine 4 decenni dopo perché non puoi innovare al livello richiesto per venire con un motore di nuova generazione effettuando semplicemente chiamate di alto livello in quello precedente.

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.