È necessario capire cosa sta succedendo a livello hardware per essere un buon programmatore?


24

Sono un programmatore autodidatta, nel caso in cui a CS 101 risponda a questa domanda. Ho imparato e usato molte lingue, principalmente per uso personale, ma occasionalmente per cose professionali.

Sembra che mi imbatto sempre nello stesso muro quando incontro problemi di programmazione. Ad esempio, ho appena posto una domanda su un altro forum su come gestire un puntatore a array restituito da una funzione. Inizialmente sto pensando che semplicemente non conosco la tecnica corretta che i progettisti del C ++ hanno impostato per gestire la situazione. Ma dalle risposte e dalle discussioni che seguono, vedo che non capisco davvero cosa succede quando qualcosa viene "restituito".

Quanto è profondo un livello di comprensione del processo di programmazione che deve raggiungere un buon programmatore?


3
Il mio consiglio: apprendere alcuni assemblaggi x86 (DOS o altro). Quindi impara a leggere alcuni dei risultati dell'assemblatore di alcuni piccoli pezzi di codice C. Poni domande se non capisci l'output. Ripetere. Questo ti costringerà a capire cosa sta succedendo a livello di CPU
Earlz,


Earlz - Vuoi dire che dovrei imparare a programmare usando il set di istruzioni x86? È questo il "livello della CPU"?
bev

Job - grazie, è stato divertente. In realtà ha commesso alcuni errori, ma solo FYI.
bev

Risposte:


33

No. Nessuno capisce cosa sta succedendo a livello hardware.

I sistemi informatici sono come le cipolle: ci sono molti livelli e ognuno dipende dal livello sottostante per il supporto. Se sei il ragazzo che lavora su uno degli strati esterni, non dovresti preoccuparti troppo di ciò che accade nel mezzo della cipolla. E questa è una buona cosa, perché il centro della cipolla cambia sempre. Finché il livello o i livelli che supportano il tuo livello particolare continuano a sembrare uguali e supportano il tuo livello, sei bravo.

Ma poi di nuovo ...

Sì. Voglio dire, non hai bisogno di capire cosa sta realmente accadendo all'interno della cipolla, ma aiuta molto avere un modello mentale di come appare l'interno di una tipica cipolla. Forse non la parte più profonda, in cui hai cancelli costituiti da transistor e simili, o il prossimo livello o due, in cui hai microcodice, un orologio, unità di decodifica delle istruzioni ecc. I livelli successivi, tuttavia, sono dove tu ho registri, la pila e il mucchio. Questi sono i livelli più profondi in cui hai molta influenza su ciò che accade: il compilatore traduce il tuo codice in istruzioni che girano a questo livello e, se lo desideri, di solito puoi scorrere queste istruzioni e scoprire cosa sta "realmente" accadendo.

I programmatori più esperti hanno in testa una versione leggermente fiabesca di questi strati. Ti aiutano a capire di cosa parla il compilatore quando ti dice che si è verificata una "eccezione di indirizzo non valido" o un "errore di overflow dello stack" o qualcosa del genere.

Se sei interessato, leggi un libro sull'architettura del computer. Non ha nemmeno bisogno di essere un libro particolarmente nuovo: i computer digitali hanno funzionato all'incirca allo stesso modo per molto tempo. Più impari a conoscere l'interno della cipolla, più stupisci che tutte queste cose funzionino! Imparare (approssimativamente) cosa sta succedendo negli strati inferiori rende la programmazione meno misteriosa e, in qualche modo, più magica. E davvero molto più divertente.

Un'altra cosa che potresti esaminare sono le cipolle incorporate. Ehm, intendo i sistemi integrati. Esistono diverse piattaforme integrate che sono abbastanza facili da usare: Arduino e BASIC Stamp sono due esempi. Si tratta sostanzialmente di microprocessori di piccole dimensioni con molte funzionalità integrate. Puoi pensarli come cipolle con meno livelli rispetto al tuo tipico PC desktop, quindi è possibile avere una comprensione abbastanza approfondita di quello che sta succedendo nell'intero sistema, dall'hardware al software.


2
Grazie. Questo sostanzialmente risponde alla mia domanda. Sono un EE che ha realizzato progetti a livello di chip (ovvero a livello di transistor) di registri, additivi, multiplexer, ecc., Quindi ottengo il livello più basso (a meno che non stiamo parlando di meccanica quantistica). Posso anche usare le lingue che conosco abbastanza bene. Ho solo un enorme divario nel livello medio (stack, heap), dove dici che il compilatore fa il suo lavoro. Dal momento che, come dici tu, voglio che la mia esperienza di programmazione sia "meno misteriosa e, ..., più magica". sembra che dovrei studiare i livelli che mi sono ancora sconosciuti.
bev

@bev: in tal caso, dovresti davvero dare un'occhiata a una piattaforma come Arduino.
Caleb,

mi dispiace essere noioso, ma ho controllato Arduino e non riesco davvero a vedere come usarlo mi aiuterebbe a capire come un compilatore tratta i puntatori e le matrici in modo diverso. Cosa non vedo?
bev

@bev: se vuoi solo scoprire come vengono chiamate le funzioni, probabilmente puoi dedicare 30 minuti a leggerlo ed essere fatto. Se vuoi avere un'idea migliore di come tutto funziona insieme, sarà più facile con un piccolo sistema. È il modo migliore per avere subito tutta la cipolla in testa. AVR, la famiglia di chip su cui si basa Arduino, è un sistema piacevole, generico, facile da usare con un set di istruzioni abbastanza piccolo da imparare senza troppi problemi.
Caleb,

Ah ok. La home page è un po 'oscura su quell'aspetto dei loro prodotti. Guarderò di nuovo.
bev

10

Non stai parlando del livello hardware, stai parlando di cosa fa veramente il compilatore con quello che gli dici di fare.

Sicuramente hai bisogno di questo livello di comprensione per capire cosa è andato storto quando non è ovvio, specialmente quando si tratta di una situazione di stomp della memoria.


Loren - Sì! Grazie per la semplice verità. Ora ho bisogno di capire il modo migliore per imparare cosa fanno i compilatori c ++ con i loro tipi di dati. A proposito, come EE, so che non è letteralmente il livello hardware. Semplicemente non sapevo come lo chiamiate voi geek CS. (Ancora non importa. Livello di compilatore?)
bev

A proposito - memoria stomp?
bev

@Bev: Hai appena dimostrato il mio punto qui - se non sai nemmeno cosa sia uno stomp della memoria, ti divertirai moltissimo a trovare un bug a causa di uno. Uno stomp della memoria è quando qualcosa scrive in un luogo che non dovrebbe e cancella (calpesta) qualunque cosa sia accaduta lì. Se sei fortunato, qualsiasi cosa colpisci è stata immediatamente vitale e almeno esplode. Se sei sfortunato, il programma continua con alcuni buchi nei suoi dati.
Loren Pechtel,

grazie per il chiarimento. Mi mostra anche quanto non so, dal momento che per quanto ne so scrivo sull'heap o sullo stack, senza un controllo più preciso.
bev

@Bev: il problema si presenta quando scrivi in ​​un posto in cui non pensi di scrivere. Hai qualcosa in pila e fai un puntatore ad esso. Lascia la routine: l'oggetto scompare, il puntatore no. Ora cosa succede quando scrivi a quel puntatore ?? Oppure hai un array di 100 articoli - cosa succede quando scrivi sull'elemento # 200?
Loren Pechtel,

6

Understanding Program Memory! = Comprensione dell'hardware

Comprensione della gerarchia della memoria == Comprensione dell'hardware


Per rispondere alla tua domanda generica: dipende. Comprendere l'hardware non può far male, ma capire che non aiuterà in tutti i casi.

Sulla base del tuo esempio, devi solo capire di più su come è suddivisa la memoria e su come è organizzata durante l'esecuzione di un programma. Comprendere l'hardware non ti aiuterà in questo senso, perché la memoria (come visibile a un programma) non rappresenta nemmeno veramente l'hardware grazie alla magia della memoria virtuale.

Se eri curioso di problemi di prestazioni basati sull'ordine in cui accedi alla memoria, ADESSO trarrai beneficio dalla comprensione dell'hardware, dall'erarchia della memoria, dai mancati cache, dagli errori di pagina e da tutta la gloriosa bontà meravigliosa che viene dall'hardware.


Stargazer - Non sono ancora al punto in cui posso preoccuparmi dei problemi di prestazioni. Presto, si spera. Grazie per i tuoi commenti.
bev

5

Se non decide di imparare un po 'di assemblatore, probabilmente si dovrebbe imparare qualcosa come 6502 assembler su un Commodore 64 (emulato, ovviamente), o 68000 su un Amiga.

Puoi avere un'idea del Commodore 64 qui ...

http://thepiratebay.org/torrent/4609238/Tag3-Saal2-Slot16_00--ID2874-the_ultimate_commodore_64_talk-Main

Il classico libro tutto quello che devi sapere è quello descritto qui ...

http://reprog.wordpress.com/2010/03/12/programming-books-part-3-programming-the-commodore-64/

Probabilmente puoi trovare una scansione PDF se ti guardi intorno.

IMO, 6502 è più facile di Z80 e 68000 è più facile di 8086 - set di istruzioni più regolari ecc.

Ma la CPU è solo un aspetto dell'hardware. Inoltre, una CPU moderna è una bestia enormemente diversa, e fa cose che sono trasparenti anche dal punto di vista dei compilatori, come la presentazione di uno spazio di indirizzi virtuale.

Un vantaggio particolare del 6502 sul C64 è che non solo la CPU è semplice, ma c'è anche qualcosa di molto semplice da hackerare con l'hardware. Mi divertivo molto a giocare con il chip musicale SID.

Quindi - è probabilmente un esercizio utile se non ci passi troppo tempo. Ho imparato 6502 assemblatore come seconda lingua quando avevo circa 14 anni, subito dopo Commodore Basic. Ma soprattutto sta ottenendo quel modello di lavoro molto semplice in modo da poter aggiungere idee più sofisticate con un minimo di incomprensioni.

Alcune cose utili che puoi imparare lavorando in assemblatore ...

  • Come funzionano i registri della CPU.
  • Come funziona l'indirizzamento della memoria, inclusa la direzione indiretta.
  • Come funziona lo stack della CPU.
  • Come funziona la logica bit a bit.
  • Come la CPU controlla i dispositivi I / O.
  • Come funzionano gli interrupt.

Una ragione particolare che consiglierei è quella di ottenere una migliore intuizione del modo in cui i semplici passaggi operano in modo completamente deterministico e meccanico e completamente senza intelligenza o buon senso. Fondamentalmente abituarsi al modello dell'esecuzione imperativa nella sua forma più pura e ostinatamente ignorante.

Proprio come utile è quello di conoscere la maggior parte di queste cose ora, però, è una domanda difficile.

Una cosa che non imparerai è come giocare bene con un'erarchia di memoria. Quelle vecchie macchine avevano per lo più un semplice modello di memoria senza livelli di cache e memoria virtuale. Inoltre non imparerai molto sulla concorrenza: erano certamente dei modi per gestirlo, ma per lo più significava interruzioni. Non devi preoccuparti di mutex ecc.

A volte, un modello mentale di come una volta funzionavano queste cose , o di come funziona l'assemblatore, può persino fuorviare. Ad esempio, pensare a un puntatore C come un indirizzo può portare a problemi di comportamento indefiniti. Il puntatore CA è normalmente implementato come un numero intero contenente un indirizzo, ma non vi è alcuna garanzia che ciò sia strettamente vero. Ad esempio, su alcune piattaforme bizzarre, puntatori diversi possono puntare su spazi di indirizzi diversi. Ciò diventa importante quando si desidera eseguire una logica aritmetica o bit a bit con due puntatori.

A meno che tu non abbia una di quelle piattaforme bizzarre, potresti non pensare che ti interessi - ma i compilatori in questi giorni hanno sempre più probabilità di sfruttare comportamenti indefiniti dagli standard per l'ottimizzazione.

Quindi un modello mentale dell'architettura di sistema può essere utile, ma è comunque importante codificare in base alle specifiche del linguaggio, non a un modello ipotetico che il tuo linguaggio e la tua piattaforma potrebbero non rispettare.

Infine, molte cose utili sul modello mentale derivano dall'idea di come i compilatori generano codice - e la generazione di codice per i linguaggi moderni è molto diversa dai compilatori piuttosto banali disponibili allora.

Questo è il mio libro preferito per quello ...

http://dickgrune.com/Books/MCD_1st_Edition/

Insieme alle cose sull'analisi e AST ecc., Copre la generazione di codice per una serie di paradigmi linguistici - imperativo, OOP, funzionale, logico, parallelo e distribuito - e anche per la gestione della memoria. Se vuoi sapere come funzionano le chiamate ai metodi polimorfici senza impantanarti nei dettagli del set di istruzioni della CPU, un libro come questo è tuo amico - e presto uscirà una nuova edizione.


Steve - wow. Sono quasi senza parole con la completezza e il focus della tua risposta alla mia domanda. Grazie mille per aver dedicato del tempo a scrivere tutto questo. Prenderò sicuramente i tuoi suggerimenti.
bev

1
Vorrei suggerire che l'assemblatore PDP-11 è un po 'più bello da imparare rispetto a tutti gli altri citati. Ciò che tutti gli altri insegnano sono i limiti imposti da risorse hardware più limitate e / o da una progettazione e una previsione dell'hardware più limitate. Qualcosa come uno della famiglia 8051 fin troppo comune insegna quanto davvero bizzarro il modello di programmazione possa arrivare su un hardware così limitato (dove la menzione di Steve di diversi spazi di indirizzi, per esempio, entra in gioco).
Greg A. Woods,

@Greg - Non ho mai avuto modo di giocare con un PDP-11, temo. Né un 8051 - Ho fatto un po 'di lavoro incorporato per un po', ma quello stava usando un chip della famiglia 8096. Ho appena dato un'occhiata qui - interessante. Ho sentito parlare dell'architettura di Harvard prima di qualche tempo, ma non avevo idea che ci fosse qualcosa di simile che era molto popolare ed è ancora in uso.
Steve314,

4

Venti anni fa era importante, ma non tanto adesso: ci sono molti più livelli di astrazione tra software e hardware moderno.

È utile sapere cose come la necessità di più thread per trarre vantaggio da più core o che l'utilizzo di più memoria di quella esistente sul sistema è una cosa negativa, ma oltre a ciò non ne hai davvero bisogno a meno che non sia il tuo lavoro a scrivere quelle astrazioni strati.

Il resto della tua domanda suggerisce che potresti essere più interessato al compilatore che all'hardware, che è un po 'diverso. Potresti imbatterti in casi in cui è importante, ma questi tendono ad essere banali (la ricorsione infinita non funziona molto bene) o il tipo di casi limite in cui puoi sentirti bene nel risolverlo ma probabilmente non incontrerai mai lo stesso problema ancora.


Sì, hai ragione, sono più preoccupato per il compilatore. Inoltre, grazie per il tuo suggerimento su più thread, più core, ecc. È appena andato nel mio file di note toLearn.
bev

Il multithreading @bev è facile da imparare, non farlo a meno che tu non debba davvero farlo e anche allora non farlo. più problemi di quanto valga la mia esperienza.
Skeith,

@Skeith - grazie per il suggerimento. Lo terrò a mente.
bev

4

Aiuta molto a conoscere e comprendere l'astrazione presentata dall'hardware, e un po 'dell'idea generale su come viene creata quell'illusione, ma cercare di capire veramente come l'hardware moderno davvero funziona è un enorme quantità di lavoro da cui si' è probabile che venga visualizzato solo un ritorno minimo.

Se perdonerai un piccolo diversivo: questo mi ricorda qualcosa che ho notato qualche anno fa. Decenni fa (fino alla fine degli anni '70 o giù di lì), la maggior parte delle persone pensava che i computer fossero a un passo dal magico - difficilmente influenzati dalle leggi della fisica, capaci di ogni genere di cose che avevano poco senso, e così via. A quel tempo, ho trascorso un bel po 'di tempo cercando (per lo più senza successo) di convincere la gente che no, non erano magici. Erano macchine abbastanza normali che facevano un numero limitato di cose in modo molto rapido e affidabile, ma per il resto erano estremamente banali.

Al giorno d'oggi, la vista della maggior parte delle persone sui computer è cambiata. Ora sono abbastanza ordinari - al punto che poche persone molto ordinarie ne hanno una comprensione pratica. Solo per esempio, un po 'di tempo fa mentre stavo cenando, ho visto / sentito un cameriere e una cameriera durante la loro pausa discutendo su cosa avrebbe dovuto trovare nel suo nuovo computer. Il consiglio che stava dando era del tutto ragionevole e realistico.

Anche la mia visione dei computer è cambiata. Sono andato a Hot Chips, e prima ancora il Forum dei microprocessori risale alla metà degli anni '90 circa. Probabilmente so di più sull'hardware microprocessore di almeno il 99% dei programmatori - e sapendo quello che faccio, io dico questo: sono non più ordinario. Essi fanno quasi rompono le leggi della fisica. Ho fatto molti test di basso livello e posso dirlo con certezza: superare l'illusione creata dalla CPU e arrivare a mostrare come funziona davvero l'hardware è spesso incredibilmente difficile. Vorrei poter pubblicare un'immagine di una delle nostre configurazioni con un computer sepolto sotto i cavi di non meno di 4 analizzatori logici solo per misurarne correttamente uno aspetto di come funziona il caching su una CPU moderna (per non parlare di una programmazione davvero fastidiosa per garantire che ciò che abbiamo misurato fosse esattamente quello che stava facendo la CPU e nient'altro).


Jerry - grazie per i tuoi commenti. Essendo un EE, sono più a mio agio con il livello di transistor rispetto ad alcuni dei livelli di astrazione più alti. Mi sto davvero chiedendo cosa devo sapere per essere un buon programmatore C ++.
bev

Quella foto sembra interessante. Perché non puoi pubblicarlo?
Mason Wheeler,

@Bev: Non devi davvero sapere nulla a livello di transistor per essere un buon programmatore. Quelle astrazioni sono lì per una ragione, e puoi quasi sempre considerare qualsiasi cosa a un livello di astrazione inferiore a quello del codice macchina / assembly come completamente irrilevante e solo supporre che funzioni.
Mason Wheeler,

@MasonWheeler: l'ho portato dove lavoravo, ma dal momento che non ci lavoro più, accedervi sarebbe probabilmente un po 'più difficile (probabilmente non impossibile - ho smesso in buoni rapporti, ma anche così. ..)
Jerry Coffin,

1

Lingue diverse funzionano a diversi livelli di astrazione dall'hardware. C e C ++ sono di livello molto basso. I linguaggi di scripting, d'altra parte, richiedono di conoscere meno i dettagli sottostanti.

Tuttavia, direi comunque che in tutti i casi, più sai, meglio sarai un programmatore. Parte della programmazione è riuscire a destreggiarsi tra più livelli di astrazione contemporaneamente.

Se stai programmando in C ++, devi avere una buona comprensione di come funziona una CPU moderna, almeno a livello di astrazione su cui lavora il compilatore. (Ci sono cose che succedono all'interno della CPU che sono trasparenti anche per il compilatore).


Scott - per "una buona comprensione di come funziona una CPU moderna .." intendi come funziona la logica digitale (ad es. Come funzionano le mappe karnaugh, le tabelle di verità e le porte AND / OR / NOR / XOR)? o intendi quali risorse utilizza direttamente il compilatore (ovvero i registri)?
bev

Conoscere di più è buono. Il vero trucco, tuttavia, è sapere che tipo di "altro" darà il massimo profitto per il tuo dollaro. Conoscere i tempi delle istruzioni, ad esempio, non sarà molto utile quando è quasi impossibile prevedere quali istruzioni verranno utilizzate dal compilatore. Imparare come usare un profiler probabilmente fornirà un rapporto costi / benefici molto migliore.
Steve314,

1
@bev - No, non penso che tu debba scendere al livello del gate. Se hai appena conosciuto l'architettura di base (memoria, bus, CPU), come carica un'istruzione, la esegue, memorizza il risultato, ecc., Probabilmente stai bene. Devi anche capire come il compilatore delinea lo spazio di memoria di un programma, incluso il modo in cui utilizza lo stack e l'heap.
Scott Whitlock,

@ScottWhitlock - Grazie - questo è proprio il tipo di consigli specifici che stavo cercando.
bev

0

Vorrei aggiungere un punto sulla progettazione generale di linguaggi di livello superiore come C.

In generale, penso che sia sicuro affermare che tali linguaggi possono essere visti come l'implementazione di una macchina astratta, ed è proprio così che Dennis Ritchie stesso ha descritto come C funziona e come il particolare design della macchina astratta C lo ha reso un linguaggio più portatile. Come tale avere una certa comprensione dell'architettura del computer e del funzionamento a livello di macchina, può essere estremamente utile anche per comprendere la macchina astratta di un linguaggio.

L'articolo di DMR Portabilità dei programmi C e del sistema UNIX è il primo che ricordo di aver discusso del modello (astratto) di macchina per C.

Penso che il documento di DMR sulla storia e lo sviluppo di C sia anche estremamente utile nel mostrare come l'hardware reale influenzi la progettazione del linguaggio, ed è forse anche un esempio della progettazione del linguaggio di programmazione iniziale: lo sviluppo del linguaggio C


Dato che sei nuovo qui sembra che pensi che questo sia un forum, sicuramente non lo è. Le tue risposte a una domanda non dovrebbero essere un punto che aggiungi, che dovrebbero essere relegate ai commenti, e la risposta dovrebbe cercare di essere una risposta completa direttamente alla domanda. Detto questo, stai dando un buon punto e questo è prezioso per le informazioni sull'argomento, forse se potessi mettere alcune righe in quella risposta alla domanda direttamente insieme a questa spiegazione sarebbe grande. Informazioni interessanti che stai condividendo qui. Benvenuti ai programmatori!
Jimmy Hoffa,

i commenti non hanno una versione e non sono permanenti, quindi sono inutili per l'aggiunta a una serie di risposte. La maggior parte dei poster sono anche inclini a ignorare l'uso dei commenti per aggiornare le loro risposte, e la maggior parte delle risposte non sono etichettate come risposte "wiki della comunità" e quindi non possono essere modificate da altri in modo tale da mantenere una certa attribuzione al / i collaboratore / i successivo / i . Inoltre, questa particolare domanda ha avviato una vera discussione, e piaccia o no, è così che vanno alcune di queste cose. Cercare di forzare ogni contributo in uno stampo è un grave fallimento del concetto di stackexchange.
Greg A. Woods,

e, tra l'altro, ho effettivamente risposto, albiet implicitamente, all'unica vera domanda dell'OP: si dovrebbe avere abbastanza comprensione dell'hardware per poter modellare la macchina astratta al centro della progettazione di un linguaggio.
Greg A. Woods,
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.