Ich bin ein Autodidakt, nur für den Fall, dass diese Frage in CS 101 beantwortet wird. Ich habe viele Sprachen gelernt und verwendet, hauptsächlich für meinen persönlichen Gebrauch, aber gelegentlich für berufliche Zwecke.
Es scheint, dass ich immer auf die gleiche Wand stoße, wenn ich Probleme beim Programmieren habe. Zum Beispiel habe ich gerade in einem anderen Forum eine Frage dazu gestellt, wie ein von einer Funktion zurückgegebener Zeiger auf ein Array zu behandeln ist. Anfangs denke ich, dass ich einfach nicht die richtige Technik kenne, die die Designer von C ++ eingerichtet haben, um mit der Situation umzugehen. Aber aus den Antworten und Diskussionen, die folgen, sehe ich, dass ich nicht wirklich verstehe, was passiert, wenn etwas "zurückgegeben" wird.
Wie tief muss ein guter Programmierer sein, um den Programmierprozess zu verstehen?
Antworten:
Nein, niemand versteht, was auf Hardwareebene vor sich geht.
Computersysteme sind wie Zwiebeln - es gibt viele Schichten, von denen jede zur Unterstützung von der Schicht abhängt, die darunter liegt. Wenn Sie der Typ sind, der an einer der äußeren Schichten arbeitet, ist es Ihnen egal, was mitten in der Zwiebel passiert. Und das ist auch gut so, denn die Zwiebelmitte ändert sich ständig. Solange die Ebene oder Ebenen, die Ihre bestimmte Ebene unterstützen, weiterhin gleich aussehen und Ihre Ebene unterstützen, sind Sie gut.
Aber dann wieder...
Ja. Ich meine, Sie müssen nicht verstehen, was wirklich in der Zwiebel vor sich geht, aber es ist sehr hilfreich, ein mentales Modell davon zu haben, wie das Innere einer typischen Zwiebel aussieht. Vielleicht nicht der tiefste Teil, in dem Sie Gates aus Transistoren und dergleichen haben, oder die nächste oder die nächste Schicht, in der Sie Mikrocode, eine Uhr, Befehlsdecodiereinheiten usw. haben. In den nächsten Schichten befinden Sie sich jedoch Ich habe Register, den Stapel und den Haufen. Dies sind die tiefsten Ebenen, auf die Sie viel Einfluss haben - der Compiler übersetzt Ihren Code in Anweisungen, die auf dieser Ebene ausgeführt werden. Wenn Sie möchten, können Sie diese Anweisungen in der Regel durchgehen und herausfinden, was "wirklich" passiert.
Die meisten erfahrenen Programmierer haben eine märchenhafte Version dieser Ebenen im Kopf. Sie helfen Ihnen zu verstehen, wovon der Compiler spricht, wenn er Ihnen mitteilt, dass eine "ungültige Adressausnahme" oder ein "Stapelüberlauffehler" oder ähnliches aufgetreten ist.
Wenn Sie interessiert sind, lesen Sie ein Buch über Computerarchitektur. Es muss nicht einmal ein besonders neues Buch sein - digitale Computer funktionieren seit langer Zeit in etwa gleich. Je mehr Sie über das Innere der Zwiebel erfahren, desto erstaunlicher wird es, dass all diese Dinge überhaupt funktionieren! Das (ungefähre) Lernen, was in den unteren Ebenen vor sich geht, macht das Programmieren weniger mysteriös und irgendwie magischer. Und wirklich mehr Spaß.
Eine andere Sache, die Sie untersuchen könnten, ist Zwiebeln eingebettet. Äh, ich meine eingebettete Systeme. Es gibt eine Reihe von Embedded-Plattformen, die sehr einfach zu bedienen sind: Arduino und BASIC Stamp sind zwei Beispiele. Hierbei handelt es sich im Grunde genommen um kleine Mikroprozessoren mit vielen integrierten Funktionen. Sie können sich Zwiebeln mit weniger Schichten als einen typischen Desktop-PC vorstellen, so dass Sie sich ein umfassendes Bild davon machen können, was im gesamten System vor sich geht, von der Hardware bis zur Software.
quelle
Sie sprechen nicht über die Hardwareebene, sondern darüber, was der Compiler wirklich mit dem macht, was Sie ihm sagen.
Dieses Verständnis ist auf jeden Fall erforderlich, um herauszufinden, was schief gelaufen ist, wenn es nicht offensichtlich ist, insbesondere, wenn es sich um eine Memory-Stomp-Situation handelt.
quelle
Grundlegendes zum Programmspeicher! = Grundlegendes zur Hardware
Grundlegendes zur Speicherhierarchie == Grundlegendes zur Hardware
Um Ihre allgemeine Frage zu beantworten: Es kommt darauf an. Es kann nicht schaden, Hardware zu verstehen, aber zu verstehen, wird nicht in allen Fällen helfen.
Anhand Ihres Beispiels müssen Sie lediglich verstehen, wie der Speicher aufgeteilt und wie er organisiert ist, wenn Sie ein Programm ausführen. Das Verständnis der Hardware hilft Ihnen in dieser Hinsicht nicht weiter, da der für ein Programm sichtbare Speicher dank der Magie des virtuellen Speichers die Hardware nicht einmal wirklich darstellt.
Wenn Sie sich für Leistungsprobleme interessieren, die auf der Reihenfolge basieren, in der Sie auf den Speicher zugreifen, profitieren Sie JETZT vom Verständnis der Hardware, der Speicherhierarchie, der Cache-Auslassungen, der Seitenfehler und all der wunderbaren Vorzüge der Hardware.
quelle
Wenn Sie sich dazu entschließen, ein bisschen Assembler zu lernen, sollten Sie wahrscheinlich 6502 Assembler auf einem Commodore 64 (natürlich emuliert) oder 68000 auf einem Amiga lernen.
Hier können Sie sich einen Eindruck vom Commodore 64 verschaffen ...
http://thepiratebay.org/torrent/4609238/Tag3-Saal2-Slot16_00--ID2874-the_ultimate_commodore_64_talk-Main
Das klassische Alles-was-Sie-wissen-müssen-Buch ist das hier beschriebene ...
http://reprog.wordpress.com/2010/03/12/programming-books-part-3-programming-the-commodore-64/
Sie können wahrscheinlich einen PDF-Scan finden, wenn Sie sich umschauen.
IMO, 6502 ist einfacher als Z80 und 68000 ist einfacher als 8086 - regelmäßigere Befehlssätze usw.
Die CPU ist jedoch nur ein Aspekt der Hardware. Auch eine moderne CPU ist ein ganz anderes Biest und erledigt Dinge, die auch aus der Sicht von Compilern transparent sind - wie das Präsentieren eines virtuellen Adressraums.
Ein besonderer Vorteil des 6502 auf dem C64 ist, dass nicht nur die CPU einfach ist, sondern es auch einige sehr einfach gibt, mit Hardware umzugehen. Früher hatte ich großen Spaß daran, mit dem SID-Musikchip herumzuspielen.
Also - es ist wahrscheinlich eine lohnende Übung, wenn Sie nicht zu viel Zeit damit verbringen. Ich habe 6502 Assembler als meine zweite Sprache gelernt, als ich ungefähr 14 Jahre alt war, direkt nach Commodore Basic. Meist geht es jedoch um ein sehr einfaches Arbeitsmodell, mit dem Sie mit einem Minimum an Missverständnissen komplexere Ideen hinzufügen können.
Einige nützliche Dinge, die Sie in Assembler lernen können ...
Ein besonderer Grund, warum ich es empfehlen würde, ist, eine bessere Vorstellung davon zu bekommen, wie einfache Schritte völlig deterministisch und mechanisch und völlig ohne Intelligenz oder gesunden Menschenverstand funktionieren. Grundsätzlich gewöhnt man sich an das imperative Ausführungsmodell in seiner reinsten und eigensinnigsten Form.
Genau wie nützlich es die meisten dieser Dinge jetzt zu wissen , ist, obwohl, ist eine schwierige Frage.
Eine Sache, die Sie nicht lernen werden, ist, wie Sie gut mit einer Erinnerungserbschaft umgehen können. Diese alten Maschinen hatten meist ein einfaches Speichermodell ohne Cache-Schichten und ohne virtuellen Speicher. Sie werden auch nicht viel über Parallelität lernen - sie waren sicherlich Möglichkeiten, damit umzugehen, aber es bedeutete meistens Unterbrechungen. Sie mussten sich nicht um Mutexe usw. kümmern.
Manchmal kann ein mentales Modell, wie diese Dinge einst funktionierten oder wie der Assembler funktioniert, sogar irreführen. Wenn Sie sich beispielsweise einen C-Zeiger als Adresse vorstellen, kann dies zu undefinierten Verhaltensproblemen führen. Ein Wechselstromzeiger wird normalerweise als Ganzzahl implementiert, die eine Adresse enthält, es gibt jedoch keine Garantie dafür, dass dies strikt zutrifft. Beispielsweise können auf einigen bizarren Plattformen unterschiedliche Zeiger auf unterschiedliche Adressräume verweisen. Dies ist wichtig, wenn Sie mit zwei Zeigern arithmetisch oder bitweise logisch arbeiten möchten.
Wenn Sie nicht über eine dieser bizarren Plattformen verfügen, denken Sie vielleicht nicht, dass Ihnen das etwas ausmacht - aber Compiler nutzen heutzutage immer häufiger undefiniertes Verhalten von Standards zur Optimierung aus.
Ein mentales Modell der Systemarchitektur kann also nützlich sein, aber es ist immer noch wichtig, auf die Sprachspezifikation zu codieren, nicht auf ein hypothetisches Modell, das Ihre Sprache und Plattform möglicherweise nicht berücksichtigt.
Eine Menge nützlicher Gedankenmodelle entstehen schließlich, wenn man sich ein Bild davon macht, wie Compiler Code generieren - und die Codegenerierung für moderne Sprachen unterscheidet sich stark von den damals erhältlichen, recht trivialen Compilern.
Dies ist ein Lieblingsbuch von mir dafür ...
http://dickgrune.com/Books/MCD_1st_Edition/
Neben den Themen Parsing und ASTs usw. wird die Codegenerierung für eine Reihe von Sprachparadigmen behandelt - Imperativ, OOP, Funktional, Logik, Parallel und Verteilt - sowie für die Speicherverwaltung. Wenn Sie wissen möchten, wie polymorphe Methodenaufrufe funktionieren, ohne sich in den Details des CPU-Befehlssatzes zu verlieren, ist ein Buch wie dieses Ihr Freund - und in Kürze ist eine neue Ausgabe erhältlich.
quelle
Vor zwanzig Jahren war es wichtig, aber jetzt nicht mehr so sehr - es gibt viel mehr Abstraktionsebenen zwischen Software und moderner Hardware.
Es ist nützlich zu wissen, wie man mehrere Threads benötigt, um mehrere Kerne auszunutzen, oder dass es eine schlechte Sache ist, mehr Speicher zu verwenden, als auf dem System vorhanden ist, aber darüber hinaus brauchen Sie es nicht wirklich, es sei denn, es ist Ihre Aufgabe, diese Abstraktion zu schreiben Lagen.
Der Rest Ihrer Frage lässt vermuten, dass Sie sich mehr mit dem Compiler als mit der Hardware beschäftigen, was ein bisschen anders ist. Es kann vorkommen, dass Sie auf Fälle stoßen, in denen es wichtig ist, aber diese sind entweder trivial (unendliche Rekursion funktioniert nicht sehr gut) oder die Art von Randfällen, in denen Sie sich bei der Lösung wohl fühlen können, aber wahrscheinlich nie dasselbe Problem haben nochmal.
quelle
Es hilft viel zu wissen und zu verstehen , die Abstraktion von der Hardware vorgestellt, und ein wenig von der allgemeinen Vorstellung davon , wie diese Illusion erzeugt wird - aber wie moderne Hardware , um wirklich zu verstehen versuchen , wirklich funktioniert , ist eine enorme Menge an Arbeit , von dem Sie‘ Es ist wahrscheinlich, dass nur eine minimale Rendite erzielt wird.
Wenn Sie eine kleine Ablenkung verzeihen: Das erinnert mich an etwas, das ich vor ein paar Jahren bemerkt habe. Vor Jahrzehnten (bis in die späten 1970er Jahre) dachten die meisten Menschen, Computer seien ein Stück weit von der Magie entfernt - kaum beeinflusst von den Gesetzen der Physik, fähig zu allen möglichen Dingen, die wenig Sinn machten, und so weiter. Zu der Zeit habe ich ziemlich viel Zeit damit verbracht (meistens erfolglos), die Leute davon zu überzeugen, dass sie keine Magie sind. Es waren wirklich ziemlich gewöhnliche Maschinen, die eine begrenzte Anzahl von Dingen sehr schnell und zuverlässig erledigten, aber ansonsten extrem banal waren.
Heutzutage hat sich die Sichtweise der meisten Menschen auf Computer geändert. Sie sind jetzt ziemlich gewöhnlich - bis zu dem Punkt, dass einige sehr gewöhnliche Leute ein praktisches Verständnis von ihnen haben. Nur zum Beispiel, vor einiger Zeit, als ich zu Abend aß, sah / hörte ich einen Kellner und eine Kellnerin in ihrer Pause darüber diskutieren, was sie in ihren neuen Computer stecken sollte. Der Rat, den er gab, war völlig vernünftig und realistisch.
Aber auch meine Sicht auf Computer hat sich geändert. Ich bin zu Hot Chips gegangen, und davor ging das Mikroprozessor-Forum etwa auf die Mitte der 90er Jahre zurück. Ich weiß wahrscheinlich mehr über Mikroprozessorhardware als mindestens 99% der Programmierer - und wenn ich weiß, was ich tue, sage ich Folgendes: Sie sind nicht mehr gewöhnlich. Sie haben brechen fast die Gesetze der Physik. Ich habe viele Tests auf niedriger Ebene durchgeführt und kann dies mit Sicherheit sagen: Es ist oft unglaublich schwierig, die Illusion zu überwinden, die die CPU erzeugt, und zu zeigen, wie die Hardware wirklich funktioniert. Ich wünschte , ich ein Bild von einem unseren Setups mit einem Computer posten könnte knapp Kabel von nicht begraben weniger als 4 Logikanalysatoren richtig zu messen , eine Aspekt, wie Caching auf einer modernen CPU funktioniert (ganz zu schweigen von einer wirklich anspruchsvollen Programmierung, um sicherzustellen, dass das, was wir gemessen haben, genau das war, was die CPU tat, und sonst nichts).
quelle
Verschiedene Sprachen arbeiten auf verschiedenen Abstraktionsebenen von der Hardware. C und C ++ sind sehr niedrig. Bei Skriptsprachen hingegen müssen Sie weniger über die zugrunde liegenden Details wissen.
Ich würde jedoch immer noch sagen, je mehr Sie wissen, desto besser sind Sie als Programmierer. Ein Teil der Programmierung besteht darin, mehrere Abstraktionsebenen gleichzeitig unter einen Hut zu bringen.
Wenn Sie in C ++ programmieren, müssen Sie ziemlich genau wissen, wie eine moderne CPU funktioniert, zumindest auf der Abstraktionsebene, auf der der Compiler arbeitet. (Es gibt Dinge in der CPU, die auch für den Compiler transparent sind).
quelle
Ich möchte einen Punkt über das allgemeine Design übergeordneter Sprachen wie C hinzufügen.
Allgemein kann man sagen, dass solche Sprachen als Implementierung einer abstrakten Maschine angesehen werden können, und Dennis Ritchie selbst hat auf diese Weise beschrieben, wie C funktioniert und wie das spezielle Design der abstrakten Maschine von C es zu einer portableren Sprache gemacht hat. Insofern kann ein gewisses Verständnis der Computerarchitektur und der Funktionsweise auf Maschinenebene äußerst hilfreich sein, um auch die abstrakte Maschine einer Sprache zu verstehen.
DMRs Arbeit Portability of C Programs and the UNIX System ist das erste, an das ich mich erinnere, das (abstrakte) Maschinenmodell für C. zu diskutieren.
Ich denke, DMRs Artikel über die Geschichte und Entwicklung von C ist auch äußerst nützlich, um zu zeigen, wie echte Hardware das Sprachdesign beeinflusst, und ist vielleicht auch ein Beispiel für frühes Programmiersprachendesign: Die Entwicklung der C-Sprache
quelle