Das Video kommt von YouTube: erst beim Abspielen verbindet sich die Seite mit YouTube (Google).
Die Anatomie eines Programms | Vom Transistor zur KI #2
Das Wichtigste aus dem Video
Tipp auf eine Zeit – das Video springt genau dorthin.
Transkriptautomatisch erstellt · 144 Zeilen
- Im ersten Teil haben wir gesehen, wie aus Strom Logik entsteht, wie Transistoren zu Gattern werden, Gatter zu addierern und wie eine CPU letztlich
- Befehle ausführt. Aber einige Fragen bleiben noch offen. Wie kommt dieser Befehl eigentlich in die CPU? Woher weiß sie, dass sie addieren soll? Woher
- kommen diese Instruktionen? Heute bauen wir die nächste mentale Ebene auf. Wir gehen von der Hardwareebene eine Stufe höher zur Codeebene und am Ende dieses
- Videos wirst du eine saubere Landkarte im Kopf haben, wie aus einem Stück Text in einer Programmiersprache ein eigentliches Programm wird. Übrigens,
- vielen lieben Dank für all eure Kommentare unter Teil 1 dieser Reihe. Ich würde mich wieder sehr über euer Feedback freuen. Ich lese tatsächlich
- jeden einzelnen Kommentar. Fangen wir ganz oben an. Ein Programm ist erstmal eine Abfolge von Anweisungen, also eine genaue Beschreibung, was passieren soll.
- Sowas wie Werteladen, addieren, vergleichen, springen, wiederholen. Für uns Menschen ist das logisch und lesbar. Für die CPU ist es das aber nicht, weil
- die CPU keine Wörter versteht und keine Ideen. Sie versteht nur Zustände, also Bits. Also da die CPU nur Nullen und Einsen versteht, müssen Programme in
- eine Form übersetzt werden, die zur Hardware passt. Und die tiefste Form, in der man wirklich sagen kann, dass es direkt ausführbar ist Maschinencode. Das
- sieht dann in etwa so aus. Maschinencode ist die Sprache, die die CPU direkt versteht. Jede Instruktion bzw. jeder Befehl ist am Ende des Tages eigentlich
- nur ein Bitmuster, also irgendeine Kombination aus Einsen und Nullen, die die CPU dekodieren kann. Sagen wir mal, ein bestimmtes Bitmuster landet jetzt
- bei der CPU. Diese Bits werden von einer Dekodierlogik verarbeitet, also einer festen Schaltung aus Transistoren und Logikgattern. Diese Schaltung ist so
- konstruiert, dass bestimmte Bitkombinationen bestimmte Leitungen aktivieren. Okay, also ihr müsst euch das so vorstellen, ihr habt am Ende eure
- CPU und da kommen jetzt bestimmte Bitmuster rein. Okay? Z.B. sowas wie 1, dass diese Kombination reinkommt, sorgt dafür, dass bestimmte Leitungen in der
- CPU getriggert werden. Wir erinnern uns zurück, in der CPU haben wir ja nur solche Transistoren und so weiter. Also Transistoren, die wir hier mit Logik
- dann dargestellt haben. Wenn jetzt eine bestimmte Kombination aus Bits da reinfließen, werden bestimmte Schalter aktiviert. Das heißt, da passiert
- physisch einfach etwas und nicht die CPU denkt sich jetzt, oh, wir müssen jetzt addieren und jetzt machen wir dieses und jenes. Sondern die CPU sieht einfach
- nur, wir bekommen jetzt diese Kombination an Bits rein, also schaltet die CPU so und so und so. Wenn z.B. ein Befehl zum Adieren dekodiert wird, dann
- bedeutet das nicht, dass die CPU Addition versteht. Es bedeutet lediglich, dass durch dieses Bitmuster eine bestimmte Kombination von
- Steuersignalen aktiviert wird. Die CPU interpretiert also nichts. Sie weiß auch nichts. Sie reagiert nur deterministisch auf elektrische Zustände. Diese Befehle
- hier sind also nur Bitmuster, die eine festverdratete Schaltung aktivieren. Für die Hardware ist es lediglich. Bestimmte Transistoren werden leitend, andere
- werden gesperrt, Ladungen verschieben sich und Spannung ändern sich. Okay, wir wissen also, dass ein Programm eine Folge von Anweisungen ist. Wir wissen,
- dass wir diese Anweisungen in Maschinencode formulieren müssen, also in Nullen und Einsen hier. Weil aber kein Mensch so programmieren kann oder
- möchte, hat man sich gedacht, man abstrahiert ein wenig weg davon. Und so ist man bei Assembly gelandet. Assembly ist quasi ein Schritt weg von binär. Das
- bedeutet, wir sagen jetzt z.B. sowas hier bedeutet im Grunde Load A. Das ist leicht, also es ist leichter zu verstehen, wenn wir einfach load A oder
- load blablabla schreiben oder Move statt diese Binär abfolgen. Im Hintergrund passiert natürlich trotzdem diese Umwandlung zu bin, aber im Grunde kann
- man damit einfacher schreiben. Das heißt, ich könnte jetzt einfach losgehen und sowas schreiben wie load A, move, sowas wie move A und so weiter.
- Ihr wisst, worauf ich hinaus will. Also so, ihr wisst, worauf ich hinaus will. Das ist viel einfacher zu programmieren als sowas hier. Assembly ist im Grunde
- also nur Machinecode, nur mit Namen statt Bitmustern. Aus einer Bitfolge wird dann sowas wie das hier. Aber die meisten Programme schreibt man nicht so,
- weil man jede Kleinigkeit selbst regeln müsste, also Datenstrukturen, Speicherverwaltung, Fehlerbehandlung und so weiter. Um Software groß und wartbar
- zu bauen, brauchst du Abstraktion. Und damit kommen wir zu höheren Programmiersprachen. In höheren Programmiersprachen wie C, RUS, Java
- oder Python formulierst du Absichten. Du sagst z.B. sowas wie: "Diese Variable soll dieses und jenes tun" oder diese Funktion, diese Schleife, diese
- Datenstruktur. Du schreibst nicht in welches Register ein Wert kommt oder wie viele Instruktionen nötig sind. Das ist genau der Punkt. Du entfernst dich
- bewusst von der Hardware, um in größeren Konzepten denken zu können und Code so zu formulieren, dass er lesbar wird für Menschen. Ich will auf einen Blick sehen
- können, was ein Code tut und ihn verstehen können. Das macht immens viele Dinge einfacher, wie z.B. Fehlersuche, aber auch das Entwickeln selbst. Ihr
- seht es hier selbst. Sowas hier kann ich z.B. super einfach lesen. Das ist z.B. ein Beispiel für CCode. Hier unten seht ihr einmal den Vergleich von dem, was
- wir gerade besprochen haben. Maschinencode ist sehr Hardware nah. Das ist das, was die Hardware wirklich am Ende des Tages braucht. Die CPU kriegt
- diese Einsen und Nullen und aktiviert damit tatsächliche Steuerleitungen in der CPU selbst. Dann geht's weiter zu Assembly. Das ist immer noch super
- Hardware nah, ne? Also, wir entfernen uns hier nicht wirklich groß. Hier ist der Sprung dann deutlich höher. Hier abstrahieren wir stärker. Dann gebe es
- noch z.B. Python und Co. Und die würden dann hier hinten irgendwo landen, ne? weil die deutlich weiter entfernt sind von der Hardware. Das macht
- Programmieren viel einfacher und skalierbarer. Aber es bedeutet auch irgendjemand oder irgendetwas muss diese abstrakte Beschreibung wieder in
- konkrete CPU Instruktionen übersetzen und das macht der Compiler. Aber bevor wir über den Compiler sprechen, will ich hier noch mal eine Sache anmerken.
- Assembly und Maschinencode sind sehr sehr Hardware nah. C++ ist im Vergleich zu den Hardware fern, aber im Vergleich zu anderen Programmiersprachen wie z.B.
- Python immer noch Hardware nah. Das heißt, wir können sagen innerhalb der Programmiersprachen selbst, ich kann hier z.B. mal so ein Teil einzeichnen,
- innerhalb der Programmiersprachen selbst könnte man diese Skala noch mal neu machen. Das heißt, man könnte sagen, Python ist irgendwo hier. Das heißt, von
- den höheren Programmiersprachen ist C oder C++ immer noch sehr hardware nah im Vergleich zu Python z.B. so, aber im Vergleich zu Assembly oder Machine Code
- ist C++ nun mal Hardware fern. Ein Compiler nimmt deinen Quelltext, also deinen Code und übersetzt ihn vor der Ausführung in Maschinencode. Das heißt,
- bevor dein Programm überhaupt startet, wird es vollständig in eine Form gebracht, die die CPU direkt ausführen kann. Dabei passiert viel mehr als nur
- Wort für Wort zu ersetzen. Der Compiler analysiert deinen Code, entscheidet, welche Instruktionen verwendet werden, welche Register benutzt werden, wie
- Speicher organisiert wird und versucht das Ganze effizient zu machen. Also wie gesagt, egal wie sehr ihr abstrahiert, egal welche Programmiersprache ihr habt,
- am Ende war geht man immer die Kette wieder zurück zum Maschinencode immer. Die CPU wird immer nur das ausführen. Sie führt nie euren Code direkt aus.
- Dieser Code wird erstmal übersetzt in dieses hier und das wird ausgeführt. Aber nicht jede Programmiersprache funktioniert so. Manche Sprachen
- übersetzen den Code nicht komplett im voraus. Stattdessen wird der Code Schritt für Schritt zur Laufzeit verarbeitet und ausgeführt. Und genau
- das macht ein Interpreter. Ein Interpreter übersetzt den Code während der Ausführung, also Zeile für Zeile. Am Ende steht aber auch hier immer eine
- Folge von Zahlen im RAM. Also egal was wir tun, egal ob Interpreter oder Compiler, am Ende steht immer der Maschinencode im RAM. Ich habe mir noch
- mal kurz die Unterschiede zwischen beiden aufgelistet. Die Entwicklung beim Compiler ist weniger flexibel, aber dafür läuft der Code sehr schnell. Aber
- warum ist die Entwicklung hier weniger flexibel? Ein Compiler übersetzt ja das komplette Programm vor der Ausführung in Maschinencode. Deshalb läuft es
- schneller, ist aber weniger flexibel, weil jede Änderung eine Neukompilierung erfordern würde. Ein Interpreter verarbeitet den Code während der
- Laufzeit Schritt für Schritt, ist dadurch also flexibler, z.B. für dynamischen Code, aber langsamer, weil die Übersetzung ständig mitläuft. Aber
- woher weiß dieser Übersetzer bzw. der Compiler und die CPU eigentlich, welche Befehle sie überhaupt nutzen darf? Sagen wir mal, ich möchte zwei Zahlen
- miteinander addieren. Gehen wir mal davon aus, meine CPU hat gar keinen Adierer, was natürlich nie der Fall sein würde, aber woher weiß ich also genau,
- was die CPU alles kann und was sie nicht kann? Woher kenne ich die Befehle, die eine CPU wirklich nutzen kann und in dem Sinne versteht? Und hier kommt die ISA
- ins Spiel, die sogenannte Instruction Set Architecture. Die ISA ist die formale Spezifikation dessen, was eine CPU versteht. Sie definiert, welche
- Instruktionen existieren, wie sie codiert werden, welche Register es gibt und wie Speicher adressiert wird. Aber wie sieht so ein Instruction Set
- eigentlich aus? Ich kann euch das mal zeigen. Und zwar könnt ihr einfach mal nach X86 OCE suchen oder X86 ISA, dann landet ihr schnell bei solchen Tabellen.
- Ihr seht hier eine Instruktion und hier den OCode dazu. Hier eine kleine Beschreibung, was diese Instruktion genau tut. Wir werden das jetzt nicht im
- Detail durchgehen, aber hier ist im Grunde eine Liste mit allen Befehlen, die eine X86er CPU im Grunde ausführen kann. Die CPU kann also nur alles
- ausführen, was hier drin gelistet ist, mehr nicht. Also jeder Code, jedes Programm, egal was ihr auf eurem PC ausführt, basiert auf Ainanderreihungen
- von diesen Instruktionen, die die CPU versteht. Das heißt, egal was ihr in eurer Programmiersprache programmiert, der Compiler bzw. Der Interpreter
- übersetzt das Ganze in so eine Instruktion hier. Das heißt, Compiler und Interpreter können nur dann zur Hardware runter, wenn klar ist, welche
- Instruktion überhaupt gültig ist. Der Compiler generiert also nicht einfach irgendeinen Maschinencode, sondern Maschinencode für eine konkrete ISA. Und
- wie vorhin erwähnt, gibt es mehrere Architekturen, z.B. X86, Arm oder Risk. Ein Beispiel für einen Armprozessor ist z.B. der Apple M1 Chip. Die typischen
- Intel oder AMD Chips sind meist X86er. Deswegen können Programme, die für X86 kompiliert wurden, nicht nativ auf einem Armprozessor ausgeführt werden, weil
- beide Architekturen unterschiedliche Befehlssätze haben. Sie benötigen dann entweder eine Neukompilierung oder eine Übersetzungsschicht, wie z.B.
- Emulatoren. Also, wir haben bis jetzt verstanden, dass ein Programm eine Folge von Anweisungen ist. Wir schreiben unsere Anweisung in der Regel so. Diese
- Anweisungen werden aber übersetzt vom Compiler oder Interpreter. So, dieser Compiler oder Interpreter nutzt dabei das Instruction Set Architecture. Das
- heißt, es weiß genau, welche Befehle es wie umwandeln muss, damit es überhaupt von der CPU ausgeführt werden kann. Jetzt schauen wir uns an, was der Linker
- macht. Bevor wir verstehen, was ein Linker macht, müssen wir kurz erklären, was eigentlich Objektdateien sind. Dazu habe ich hier unten eine kleine Skizze
- gemacht. Ich glaube, die ist eigentlich ganz nützlich. Links siehst du zwei CDien, main.c C und math. Der Compiler übersetzt diese Dateien nicht direkt zu
- einem fertigen Programm. Stattdessen wird jede Datei einzeln kompiliert. Das Ergebnis sind sogenannte Objektdateien. Hier main. Math. In diesen Objektdateien
- steckt bereits echter Maschinencode. In Main. Z.B. in der Punkt Text Section der Befehl Call AD. Ihr seht es hier rot markiert, aber entscheidend ist Add ist
- hier nur ein Symbol. In der Symboltabelle steht, dass Ad extern ist, also irgendwo anders definiert wird. Zusätzlich gibt es hier so einen
- weiteren Eintrag, der sagt, an dieser Stelle muss später noch eine Adresse gesetzt werden und zwar bei Ad, weil wir eben nicht wissen, wo sich dieses Ad
- befindet. In math. Dagen sehen wir die Definition von Ad. Dort steht die eigentliche Implementierung. Wichtig, beide dieser Objektdateien enthalten
- schon Maschinencode. Ich habe das jetzt hier so dargestellt, damit wir es einfacher lesen können. Wichtig, sie wissen aber noch nichts voneinander. Vor
- allem kennt main. Noch nicht die konkrete Speicheradresse von AD. Und genau hier kommt der Linker ins Spiel. Der Linker nimmt diese einzelnen
- Objektdateien, führt ihre Textbereiche zusammen, gleicht die Symboltabelle ab und löst alle offenen Referenzen auf. Das Symbol Add wird durch eine konkrete
- Adresse ersetzt. Hier z.B. 4050. Das Ergebnis wäre erst jetzt das ausführbare Programm. Wichtig, hier drin steht Text, aber in Wirklichkeit sind
- das auch wieder Nullen und Einsen. Ich habe das jetzt hier so hingeschrieben, damit wir einmal den Übergang hier verstehen können. Man kann es sich also
- so merken. Der Compiler erzeugt einzelne noch unvollständige Bausteine. Der Linker verbindet sie und löst alle offenen Verweise auf und daraus entsteht
- ein vollständiges startbares Programm. Aus vielen Dateien wird also ein Binary, also eine ausführbare Datei. Somit kommen wir auch direkt schon zum Punkt
- Executable. Ein Executable ist eine Datei mit Struktur. Sie enthält also Maschinencode Daten, Metadaten über Segmente, ein Einstiegspunkt und häufig
- Referenzen auf weitere Libraries. Sie ist so gebaut, dass das Betriebssystem sie später in den RAM laden und starten kann. Aber wichtig, eine Datei ist noch
- kein Prozess. Ein Binary ist also noch nicht laufend. Es ist also einfach nur eine Beschreibung dessen, was laufen soll. Es ist also auch hier wie eine Art
- Rezept. Das Rezept wird aber noch nicht ausgeführt. Es liegt jetzt erstmal nur im Speicher. Bevor wir aber zum Betriebssystem übergehen, fehlen noch
- drei Ebenen, die erklären, wie diese Binärwelt organisiert ist. Und damit kommen wir zum Application Binary Interface Kurz Abi. Die Abi ist im
- Grunde die technische Vereinbarung auf Maschinencode, damit Programme und Libraries miteinander reden können. Also, stellt euch mal vor, ich schreibe
- jetzt meinen Code und ich möchte irgendwas auf dem Bildschirm ausgeben. In der Regel läuft das so ab. Ich würde jetzt hier reingehen und z.B. sowas
- sagen wie Print F und dann hello. So kann ich z.B. was auf dem Bildschirm ausgeben. Dieses Add hier habe ich ja vorhin selbst definiert, aber Print F
- habe ich nicht selbst definiert. Er stammt nämlich aus der C Standardbibliothek. Ihr seht es hier oben. Aber sagen wir mal, mein Code
- wurde vielleicht heute kompiliert und die Library hier oben wurde schon vor Jahren kompiliert. Trotzdem müssen beide auf Maschinenebene perfekt
- zusammenarbeiten. Aber wie? Woher weiß Print F, wo seine Parameter liegen, wie Rückgabewerte zurückgegeben werden, wie der Stack aussieht, wie man ins
- Betriebssystem springt und und. Und genau hier kommt diese Abi ins Spiel. Die Abi legt also fest, wie fertig kompilierte Programme und Libraries,
- also Bibliotheken miteinander sprechen. Nicht auf C-Ebene, nicht auf Quellcode, sondern auf Binärebene. Wichtig, diese Abi wird nicht vom Linker gemacht. Abi
- ist im Grunde das Regelwerk, an das sich Compiler, Libraries und das Betriebssystem halten. Es ist also wie eine Art Spezifikation oder Dokument,
- das genau festlegt, welche Register dürfen für Parameter genutzt werden, wo sollen Rückgabewerte landen, wie soll der Stack ausgerichtet werden, was der
- Stack ist, dazu kommen wir gleich noch. Wie sollen Systemcalls aussehen und wie soll am Ende eine Executable strukturiert sein? Der Compiler
- implementiert diese Regeln beim Erzeugen des Codes. Die Standardbibliothek wurde nach denselben Regeln kompiliert und das Betriebssystem erwartet dieselben
- Regeln. Warum ist das Ganze so entscheidend? Stell dir vor, dein Compiler würde Parameter im bestimmte Register übergeben und die Library würde
- sie aber ganz woanders erwarten. Dann würde Print F komplett falsche Werte lesen und es würde sofort crashen. Dass das nicht passiert, liegt darin, weil
- beide sich an dieselben Regeln halten bzw. die AI. Okay, genug von der AI. Machen wir weiter. Sprechen wir jetzt über Speicherse. Ein Programm ist im
- Speicher nicht einfach ein chaotischer Block. Neben Code und statischen Daten gibt es zwei besondere wichtige Bereiche, den Stack und den Hieb. Der
- Stack ist der Bereich für Funktionsaufrufe. Er funktioniert nach dem Prinzip Last in, first out. Also das, was zuletzt hineingelegt wurde,
- kommt zuerst wieder heraus. Stell dir einen Stapelt Teller vor. Du legst oben einen neuen Teller drauf, dann noch einen weiteren und dann noch einen
- weiteren und wenn du einen brauchst, nimmst du wieder den obersten weg. Genauso organisiert sich der Stack. Jedes Mal, wenn eine Funktion gestartet
- wird, legt das System dort ihre lokalen Variablen ab und die Information, wo es nach dem Ende der Funktion zurückspringen soll. Wenn die Funktion
- fertig ist, wird dieser Speicher automatisch wieder freigegeben. Der Stack wächst also bei jedem Funktionsaufruf und schrumpft wieder
- sobald die Funktion endet. Das macht den Speicher sehr effizient. Der Hieb hingegen funktioniert anders. Er ist für Speicher gedacht, der zur Laufzeit
- flexibel angefordert wird, z.B. für größere oder dynamische Datenstrukturen. Anders als beim Stack wird dieser Speicher nicht automatisch freigegeben.
- Das Programm fordert ihn aktiv an. In C würde man das z.B. über Mallock machen, also Memory Allocation. Wichtig, man muss den Speicher selber auch wieder
- freigeben. Der Hieb wird dadurch flexibler, aber auch aufwendiger zu verwalten. Warum entstehen hier jetzt aber so viele Speicherfehler? Im Grunde
- liegt es hier auf der Hand, weil du den Speicher selbst organisieren musst. Das heißt, du musst ihn selbst reservieren und selbst wieder löschen, wenn du ihn
- nicht brauchst. Sagen wir mal, ich reserviere Speicher für drei Bereiche, für drei Zahlen. Okay, ich mache jetzt mal so. Ich sag, ich will jetzt drei
- Dinger hier reservieren im Hieb. Das sollen ganze Zahlen sein und ich reserviere jetzt einfach mal. Wenn der Nutzer jetzt aber fünf Werte eingibt, du
- aber nicht sauber überprüfst, ob er genau drei eingibt oder nicht, dann hast du ein Problem, weil er jetzt fünf Werte reingibt und damit deinen Speicher
- überschreibt. Das heißt, er sorgt jetzt dafür, dass Werte überlaufen. So viiel zu Speichersegmenten. Kommen wir jetzt zum letzten Punkt und zwar zur Runtime.
- Die Runtime ist die Laufzeitumgebung, die ein Programm während der Ausführung unterstützt. Sie übernimmt die grundlegenden Aufgaben, die fast jedes
- Programm braucht. Dazu gehören z.B. Dinge wie das Starten des Programms selbst, die Initialisierung von Speicher, Standardfunktion für z.B. ein
- und Ausgabe auf dem Bildschirm, das ist das, was wir uns hier unten angeschaut hatten. In der Sprache C ist das z.B. die C Runtime. Bevor deine Funktion
- überhaupt startet, hat die Runtime bereits den Stack vorbereitet, globale Variablen initialisiert und die Umgebung eingerichtet. Erst danach wird dein Code
- ausgeführt. In anderen Sprachen ist diese Schicht noch deutlich sichtbarer. In Java läuft dein Code nicht direkt auf der CPU, sondern in der JVM. In Python
- wird dein Code vom Interpreter ausgeführt. Diese Komponenten sind ebenfalls Runtime Systeme. Wichtig ist, die Runtime ersetzt nicht das
- Betriebssystem, sie sitzt darüber. Wenn dein Programm Speicher braucht, ruft die Runtime letztlich Funktionen des Betriebssystems auf. Man kann es sich so
- vorstellen. Dein Code beschreibt, was passieren soll. Die Runtime organisiert, wie es innerhalb der Sprache abläuft und das Betriebssystem stellt die echten
- Ressourcen bereit. Die Runtime ist also die vermittelnde Schicht zwischen Sprache und System. Wenn wir einmal zurückblicken, dann haben wir heute eine
- sehr wichtige Schicht aufgebaut. Lassen wir einmal Teil 1 und Teil 2 kurze Revue passieren. Ganz unten stehen Strom und Transistoren. Transistoren bilden Gat.
- Gat bilden Adierer und Logik und daraus entsteht die CPU. Die CPU verarbeitet nur elektrische Zustände deterministisch. Darüber liegt der
- Maschinencode. Bitmuster, die nichts bedeuten, sondern festverdratete Steuerleitungen aktivieren. Darüber liegt Assembly, dieselbe Welt nur mit
- lesbaren Namen. Darüber liegen höhere Programmiersprachen, indem wir Absichten formulieren, statt Register zu verwalten. Dann kommen Compiler und
- Interpreter, die diese Abstraktion wieder herunterbrechen, zurück auf eine konkrete Instruction Set Architecture. Der Linker verbindet dann einzelne
- Bausteine. Das Ergebnis ist ein strukturiertes Binary mit klarer Abi, klaren Speichersegmenten, Stack und Hieb. Die Runtime unterstützt das Ganze
- während der Ausführung und erst dann übernimmt das Betriebssystem, was wir uns im nächsten Video anschauen werden. Wenn dir diese Reihe hilft, solche
- komplexen Systeme klarer zu sehen, dann schreib es mir wieder in die Kommentare. Ich lese wirklich jeden Kommentar und bin happy über Feedback. Wie gesagt, im
- nächsten Teil schauen wir uns Betriebssysteme genauer an und bis dahin stay safe und bis zum nächsten
Zum Nachlesen
MaschinenspracheMit einem Assembler: Assemblersprachen formulieren die Prozessorbefehle des Maschinencodes als Mnemonics in einer einfachen Syntax. Dieser Quelltext wird …
ProgrammcodeAls Programmcode (oder Programmkode) werden die Anweisungen bezeichnet, die im Rahmen der Softwareentwicklung für ein bestimmtes Computerprogramm oder einen …
SystemprogrammierspracheAls Systemprogrammiersprache werden Programmiersprachen bezeichnet, welche zur Systemprogrammierung verwendet werden können. Sie stehen in Kontrast zu …
ProzessorAufbau und Funktionale Einheiten · Hauptprozessor (CPU) und Mehrprozessorkerne · Steuer- bzw. Leitwerk · Rechenwerk und Register · Datenleitungen · Caches und MMU.