31
Allgemeine Grundlagen der Programmierung Boris Schäling

Allgemeine Grundlagen Der Programmierung

Embed Size (px)

Citation preview

Page 1: Allgemeine Grundlagen Der Programmierung

Allgemeine Grundlagender Programmierung

Boris Schäling

Page 2: Allgemeine Grundlagen Der Programmierung

Allgemeine Grundlagen der ProgrammierungBoris Schäling

Veröffentlicht 2010-02-03Copyright © 2001-2010 Boris Schäling [mailto:[email protected]]

Page 3: Allgemeine Grundlagen Der Programmierung

iii

InhaltsverzeichnisInhalt ......................................................................................................................... ivVoraussetzungen ........................................................................................................... v1. Programmiersprachen ................................................................................................. 1

Aufbau und Bestandteile ........................................................................................ 1Variablen ............................................................................................................. 2Operatoren ........................................................................................................... 3Kontrollstrukturen ................................................................................................. 4Funktionen ........................................................................................................... 6Strukturen ............................................................................................................ 7Sonstige Bestandteile ............................................................................................. 7Sprach-Entwicklung ............................................................................................... 8Compiler und Interpreter ........................................................................................ 8Aufgaben ............................................................................................................. 9

2. Zahlensysteme ......................................................................................................... 11Allgemeines ....................................................................................................... 11Zahlensysteme und der Computer ........................................................................... 11Das Binärsystem ................................................................................................. 12Das Hexadezimalsystem ....................................................................................... 12Vom Binärsystem zum Hexadezimalsystem und zurück .............................................. 13Zahlensysteme in der Praxis .................................................................................. 13Aufgaben ........................................................................................................... 15

3. Rechnerarchitektur ................................................................................................... 17Allgemeines ....................................................................................................... 17Digitale Grundschaltungen .................................................................................... 17Der Halbaddierer ................................................................................................. 18Der Volladdierer ................................................................................................. 19Addition beliebiger Binärzahle ............................................................................... 19Akku, ALU und Rechenwerk ................................................................................ 20Prozessor ........................................................................................................... 20Von-Neumann-Rechner ........................................................................................ 20Aufgaben ........................................................................................................... 21

4. Programmaufbau ..................................................................................................... 22Allgemeines ....................................................................................................... 22Multithreading .................................................................................................... 22Polling ............................................................................................................... 25Multiplexing ....................................................................................................... 25Asynchrone Ein- und Ausgabe ............................................................................... 26Aufgaben ........................................................................................................... 26

Page 4: Allgemeine Grundlagen Der Programmierung

iv

InhaltWas Sie lernen werden

Dieses Buch führt Sie langsam und verständlich in die Thematik der Programmierung ein. Ihnen wirderklärt, was Programmiersprachen sind, aus welchen einzelnen Bestandteilen sie bestehen und wieSie sie einsetzen, um einfache kleine Programme zu schreiben. Außerdem werden Sie in die Geheim-nisse der Zahlensysteme eingeweiht und lernen, wie man Zahlen vom Dezimalsystem ins Binär- undHexadezimalsystem umrechnet und zurück. Eine Einführung in den Aufbau elektronischer Schaltun-gen wird Ihnen zeigen, warum Computer überhaupt in der Lage sind, Berechnungen durchzuführen.Abschließend werden Ihnen verschiedene Möglichkeiten vorgestellt, wie Programme im Allgemeinenintern organisiert und aufgebaut sein können.

Page 5: Allgemeine Grundlagen Der Programmierung

v

VoraussetzungenWas Sie wissen müssen

Für das Verständnis dieses Buchs sollten Sie grundlegende Kenntnisse im Umgang mit Ihrem Betrie-bssystem besitzen, also beispielsweise problemlos Dateien erstellen und speichern und Anwendungenausführen können.

Page 6: Allgemeine Grundlagen Der Programmierung

1

Kapitel 1. ProgrammiersprachenAufbau und Bestandteile

Werkzeuge zur Verarbeitung von InformationenWenn man Programmiersprachen unter die Lupe nimmt und sie miteinander vergleicht, stellt manschnell fest, dass es große Ähnlichkeiten gibt. Programmiersprachen bestehen aus ähnlichen Bestand-teilen. Wenn man verstanden hat, warum es diese Bestandteile gibt und welchen Sinn sie haben, ist esspäter kein Problem mehr, neue Programmiersprachen zu erlernen. Die Syntax, sprich die technischenBegriffe, sind von Programmiersprache zu Programmiersprache unterschiedlich, die dahinterstehen-den Konzepte, auf die es ankommt, sind es - natürlich bis auf Ausnahmen - nicht.

Wozu braucht man Programmiersprachen? Was ist der Sinn und Zweck von Programmierspra-chen? Programmiersprachen werden benötigt, um Computer-Anwendungen zu entwickeln. Compu-ter-Anwendungen können ganz allgemein auf einen kleinsten gemeinsamen Nenner gebracht werden:Computer-Anwendungen verarbeiten Informationen. Es ist völlig egal, ob Sie es mit einem Browser,einer Textverarbeitung, einem Computerspiel oder einer Steuerungsanlage für Atomkraftwerke zu tunhaben, letztendlich geht es schlicht und ergreifend um das Verarbeiten von Informationen.

Um Computer-Anwendungen zu entwickeln, die Informationen verarbeiten können, benötigt man ent-sprechende Werkzeuge. Programmiersprachen stellen diese Werkzeuge zur Verfügung.

Informationen können nur dann sinnvoll verarbeitet werden, wenn sich Informationen auch speichernlassen. Computer-Anwendungen müssen in der Lage sein, sich Informationen merken zu können,um beispielsweise später im Laufe des Programms auf vorher gespeicherte Informationen wiederzurückgreifen zu können. Würden nämlich zum Beispiel irgendwelche komplizierten Berechnungenzu einem Zwischenergebnis führen, auf das anderweitige Berechnungen im Programm folgen, bevorspäter mit dem Zwischenergebnis weitergerechnet wird, muss dieses Zwischenergbnis für später imProgramm irgendwo festgehalten werden. Ohne das Speichern von Informationen würden errechneteErgebnisse andauernd verloren gehen. Das Werkzeug, das sämtliche Programmiersprachen zur Ver-fügung stellen, um Informationen zeitweilig in einem Programm zu speichern, nennt sich Variablen.

Während Variablen lediglich das Speichern von Informationen ermöglichen, müssen Programmier-sprachen noch mehr Werkzeuge zur Verfügung stellen - denn Computer-Anwendungen sollen ja nichteinfach nur Informationen speichern, sondern diese verarbeiten. Jede Programmiersprache stellt dahereine ganze Reihe vordefinierter Operatoren zur Verfügung. Diese Operatoren sind mehr oder wenigerkryptische Zeichen, denen eine ganz bestimmte Bedeutung in der Programmiersprache zugewiesenist. Mit diesen Operatoren können nun Variablen verknüpft werden. Je nach Operator wird diese Ver-knüpfung auf die eine oder andere Weise ausgeführt und führt schließlich zu einem neuen Ergebnis.Die Information in den beiden verknüpften Variablen wird vom Operator verrechnet und kann dannzum Beispiel in einer dritten Variablen gespeichert werden.

Mit Variablen und Operatoren kann man schon eine ganze Menge anstellen und bereits richtige Com-puter-Anwendungen entwickeln - zum Beispiel ein mathematisches Programm, das Zahlen addiert.Wenn Sie jedoch eine Software schreiben möchten, die den Anwender auffordert, ein Passwort ein-zugeben, und in Abhängigkeit des Passworts Zugriff auf geschützte Dateien ermöglicht, so reichenVariablen und Operatoren nicht aus, ein derartiges Programm zu schreiben. Das Problem ist, dassSie in Ihrem Programm eine Entscheidung treffen müssen. Je nach eingegebenem Passwort muss derZugriff auf die Dateien gestattet werden oder eben nicht - das hängt ganz davon ab, ob der Anwenderdas richtige Passwort kennt. Glücklicherweise bieten Programmiersprachen nun auch ein Werkzeugan, das Bedingungen überprüft und in Abhängigkeit dieser unterschiedlichen Code ausführt. DiesesWerkzeug nennt sich Kontrollstrukturen. Mit Kontrollstrukturen können Bedingungen überprüft wer-den, also zum Beispiel die Eingabe des Anwenders daraufhin, ob sie mit dem tatsächlichen Passwortübereinstimmt. Mit Kontrollstrukturen sind Verzweigungen im Code möglich - Code kann übersprun-gen oder sogar wiederholt werden. Programme laufen also nicht mehr stupide von oben nach unten

Page 7: Allgemeine Grundlagen Der Programmierung

Programmiersprachen

2

ab, sondern verzweigen je nach Abhängigkeit von Bedingungen, die in Kontrollstrukturen überprüftwerden.

Variablen, Operatoren und Kontrollstrukturen - eigentlich brauchen Sie schon gar nicht mehr, umComputer-Anwendungen zu entwickeln. Dummerweise ist die Software-Entwicklung eine recht kom-plizierte Geschichte. Je größer die zu entwickelnden Programme werden, umso schwieriger wird es,fehlerfreien Code zu schreiben. Die Komplexität in Programmen, die aus tausenden Code-Zeilenbestehen, lässt sich kaum mehr vom menschlichen Programmiererkopf erfassen. Programmierspra-chen bieten daher ein weiteres Werkzeug an, um die Komplexität in den Griff zu kriegen. Der Code,den der Programmierer entwickelt, lässt sich in kleine übersichtliche Häppchen zerlegen. Anstatt alsodas gesamte Programm in einem Wisch zu schreiben, wird es in kleine Module zerlegt, die sich dannwieder gut überblicken und verstehen lassen. Das Werkzeug, um das es geht, wird in Programmier-sprachen Funktionen genannt. Funktionen gliedern den Code und machen ihn übersichtlicher.

Es gibt Programmiersprachen, die sind an dieser Stelle fertig. Sie bieten Variablen, Operatoren, Kon-trollstrukturen und Funktionen und damit alles, was Sie benötigen, um vollwertige Computer-Anwen-dungen zu entwickeln. Derartige Programmiersprachen werden prozedurale Programmiersprachengenannt. Prozedur ist ein anderer Begriff für Funktion und bezieht sich darauf, dass das höchste undbeste Gestaltungsmittel in diesen Programmiersprachen eben die Funktionen sind. Bekannte prozedu-rale Programmiersprachen sind C, Pascal und Basic.

Leider gibt es in der heutigen modernen Software-Entwicklung das Problem, dass sie so ungeheuerkomplex ist, dass Funktionen als Strukturierungsmittel nur ein Tropfen auf den heißen Stein sind.Anwendungen, die aus Millionen von Code-Zeilen bestehen, benötigen bessere Strukturierungsmög-lichkeiten, damit die Programme überhaupt noch sinnvoll weiterentwickelt werden können. In denvergangenen Jahren hat sich die Objektorientierung durchgesetzt und nochmal ein Werkzeug auf dieprozeduralen Programmiersprachen draufgesetzt. Code wird nun nicht mehr mit Hilfe von Funktio-nen übersichtlich gestaltet, sondern mit Klassen und Objekten. Die Objektorientierung stellt heute denheiligen Gral dar und ist das leistungsfähigste Instrument, das wir momentan haben, um Software zuentwickeln. So sind beispielsweise Computer-Anwendungen wie der Microsoft Internet Explorer oderdie Programme aus Microsoft Office alle objektorientiert programmiert. Bekannte objektorientierteProgrammiersprachen sind C++, Java und Smalltalk.

Im Folgenden lernen Sie verschiedene Bestandteile von Programmiersprachen etwas näher kennen.Anhand der Programmiersprache Javascript wird Ihnen gezeigt, wie man tatsächlich mit Variablen,Operatoren, Kontrollstrukturen und Funktionen umgeht und was Sie sich also wirklich unter der Pro-grammierung vorzustellen haben.

Variablen

InformationstöpfeUm Informationen in Programmen speichern zu können, benötigen Sie spezielle Töpfe: Variablen. Siekönnen als Programmierer jederzeit so viele Variablen herbeizaubern wie Sie möchten. Jede Variablestellt einen eigenen Behälter dar, in den Sie eine Information ablegen und sie im Laufe des Programmsspäter wieder herausholen können. In der Programmiersprache Javascript gehen Sie wie folgt vor, umeine Variable anzulegen, sprich um einen Topf herbei zu zaubern.

var topf;

Mit dieser einen Zeile zaubern Sie eine Variable namens topf herbei. Sie können nun in Ihrem Pro-gramm auf diese Variable topf jederzeit zugreifen und in ihr eine Information speichern. Variablenwerden in vielen Programmiersprachen immer nach dem gleichen Schema angelegt: Zuerst geben Sieeinen Datentyp an. In diesem Beispiel lautet der Datentyp var. Der Datentyp legt fest, welche Artvon Information in der Variablen gespeichert werden kann. Es gibt Programmiersprachen, in denenSie abhängig von der Art der Information, die Sie speichern wollen, einen ganz bestimmten Topfbrauchen. Zu diesen Programmiersprachen zählen beispielsweise C, C++ und Java. In Javascript -der Programmiersprache, in der die vorliegenden Beispiele in diesem Buch geschrieben sind - gibt

Page 8: Allgemeine Grundlagen Der Programmierung

Programmiersprachen

3

es hingegen nur den einen Datentyp var. Es spielt in Javascript für eine Variable keine Rolle, welcheArt von Information Sie in ihr speichern möchten. Eine Variable in Javascript kann also zum Beispieleinen Buchstaben speichern oder eine Zahl oder auch ein Wort. In einer anderen Programmiersprachebräuchten Sie eventuell für einen Buchstaben auch tatsächlich einen Topf, der Buchstaben speichernkann, und für eine Zahl wiederum eine andere Art von Topf, der eben Zahlen speichern kann. Nichtsanderes drückt der Datentyp aus - er legt fest, welche Art von Information in einer Variablen gespei-chert werden kann.

Dem Datentyp folgt ein Variablenname. Variablen müssen irgendwelche Namen erhalten, damit manauf sie jederzeit in einem Programm zugreifen und sie identifizieren kann. Im obigen Beispiel hatdie Variable einfach den Namen topf erhalten. Beachten Sie, dass Javascript wie auch viele andereProgrammiersprachen wie C, C++ und Java Groß- und Kleinschreibung berücksichtigt.

Ebenfalls typisch für viele Programmiersprachen ist das Semikolon, das am Zeilenende angegebenwird. Mit dem Semikolon wird eine Anweisung beendet und abgeschlossen. Während Javascript esmit dem Semikolon nicht ganz so genau nimmt und auch mal darüber hinwegsieht, wenn es fehlt,müssen jedoch in C, C++ und Java Semikolons unbedingt gesetzt werden.

Während es in der Programmiersprache Javascript wie eben gesehen nur den einen Datentypen vargibt, muss beispielsweise in C++ einer Variablen, die Zahlen speichern können soll, der Datentyp intgegeben werden.

int zahlentopf;

Benötigen Sie in C++ jedoch eine Variable, die ein Wort speichern können soll, so müssen Sie derVariablen den Datentyp string geben.

string worttopf;

C++ ist eine streng typisierte Programmiersprache. Das heißt, Variablen haben keinen allgemeinenDatentyp wie in Javascript und können jede Art von Information speichern, sondern sie besitzen einenganz konkreten Datentyp und können daher auch nur eine ganz bestimmte Art von Information spei-chern.

Der Vorteil der streng typisierten Programmiersprachen ist, dass Programmierfehlern vorgebeugtwird. Es ist in C++ nicht möglich, versehentlich in der oben angelegten Variablen zahlentopf einWort zu speichern - das funktioniert aufgrund des Datentypen nicht. Der Nachteil ist jedoch, dass Siebeim Anlegen von Variablen sich darüber im Klaren sein müssen, welche Art von Information Siespäter speichern möchten. Davon hängt nämlich ab, welchen Datentyp Sie überhaupt angeben müssen.

Operatoren

Informationen verknüpfen und verarbeitenWie man Variablen anlegt wissen Sie nun. Sie können nun jederzeit so viele Variablen anlegen, wieSie möchten, und darin Informationen speichern. Mit der Speicherung von Informationen allein istes jedoch nicht getan. Schließlich soll Ihre Anwendung Informationen verarbeiten, also zum Beispieleine Berechnung durchführen und zwei Zahlen addieren. Sie können mit Variablen Zahlen speichern,aber wie werden sie addiert?

Informationsverarbeitende Vorgänge wie zum Beispiel die Addition von Zahlen sind durch Operato-ren möglich. Jede Programmiersprache bietet Operatoren an - ohne Operatoren können keine Infor-mationen verarbeitet werden. Die meisten Programmiersprachen besitzen ähnliche Operatoren, diejeweils die gleiche Bedeutung haben. Wenn Sie beispielsweise wissen, wie die Operatoren in Javas-cript funktionieren, dann kennen Sie eigentlich auch schon fast alle Operatoren aus Java, C und C++.Im Folgenden sehen Sie ein paar Operatoren der Programmiersprache Javascript im Einsatz.

var i = 1, j = 2, k;

Page 9: Allgemeine Grundlagen Der Programmierung

Programmiersprachen

4

k = i + j;k = i - j;k = i * j;k = i / j;k += j;k -= i;i << j;

k = i > j;

k = (i + j) * 2;

Operatoren können nach ihrer Funktion gegliedert und verschiedenen Gruppen zugeordnet werden.So gibt es beispielsweise eine Gruppe arithmetischer Operatoren, deren Sinn und Zweck die Ausfüh-rung von Grundrechenarten mit +, -, * und / ist. So wie arithmetische Operatoren Zahlen verrechnenkönnen, können logische Operatoren wie &&, || und ! Wahrheitswerte verrechen. Bitweise Opera-toren wie &, |, ~ und ^ arbeiten sehr maschinennah. Mit diesen Operatoren kann man in Variablendie kleinsten Informationseinheiten bearbeiten, die der Computer besitzt - nämlich Bits. Eine andereGruppe von Operatoren - die sogenannten Vergleichsoperatoren wie ==, !=, > und < - ermöglichenwiederum den Vergleich von Werten.

Neben diesen Operatoren besitzt jede Programmiersprache eine Präzedenz-Tabelle, in der jedem Ope-rator per Definition einfach eine Priorität zugewiesen ist. Diese Präzedenz-Tabellen sind insofern ent-scheidend, als dass sie klar vorgeben, in welcher Reihenfolge Operatoren ausgeführt werden, wennmehrere in einer einzigen Code-Anweisung verwendet werden. So kann beispielsweise die Präze-denz-Tabelle einer Programmiersprache festlegen, dass der * eine höhere Priorität besitzt als das +.Dies bedeutet nichts anderes als die Regel "Punkt vor Strich" aus der Mathematik: Eine Multiplikationwird gegenüber einer Addition bevorzugt ausgeführt. Sinnvollerweise sehen Programmiersprachenwie Javascript, Java, C und C++ genau dies auch vor.

Der Operator mit der höchsten Priorität ist für gewöhnlich die runde Klammer (). Das bedeutet,dass eine Klammerung immer bevorzugt und zu allererst ausgeführt wird. Das heißt auch, dass sichmit den Klammern die Ausführungsreihenfolge von Operatoren, wie sie durch die Präzedenz-Tabellevorgegeben ist, ändern lässt. So wie in der Mathematik kann also durch geeignete Klammerung aucheine Addition zuerst ausgeführt werden, bevor die Summe dann mit einem anderen Wert multipliziertwird.

Kontrollstrukturen

Abhängig von Bedingungen unterschiedlichen Codeausführen

Mit Hilfe von Variablen und Operatoren können Sie nun Informationen wie beispielsweise Zahlenverarbeiten. Diese Verarbeitung erfolgt bis dato aber nur linear. Der Computer arbeitet Ihre Anwei-sungen im Programm von oben nach unten ab, und zwar jede Anweisung genau einmal. Wenn Siejedoch beispielsweise einen Passwortschutz entwickeln möchten, muss abhängig von der Eingabe desAnwenders entweder Zugang zur gesicherten Ressource gewährt werden oder aber nicht. Verzwei-gungen des Programmflusses sind mit Kontrollstrukturen möglich. Auch folgende drei Code-Beispie-le sind in der Programmiersprache Javascript geschrieben.

<html> <head> <title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript"> var passwort = "abc"; var eingabe = prompt("Geben Sie ein Passwort ein.");

Page 10: Allgemeine Grundlagen Der Programmierung

Programmiersprachen

5

if (eingabe == passwort) { alert("Passwort ok!"); } else { alert("Passwort falsch!"); } </script> </head> <body> </body></html>

Die if-else-Anweisung ermöglicht eine einfache Überprüfung einer Bedingung. Ist die Bedingungwahr, wird der Anweisungsblock, der durch die geschweiften Klammern definiert wird, hinter dem ifausgeführt. Ist die Bedingung falsch, wird der Anweisungsblock hinter dem else ausgeführt. Ist derjeweilige Anweisungsblock ausgeführt worden, setzt die Programmausführung hinter der if-else-Anweisung fort.

<html> <head> <title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript"> var passwort = "abc"; var eingabe = prompt("Geben Sie ein Passwort ein.");

while (eingabe != passwort) { eingabe = prompt("Das Passwort ist falsch. Bitte nochmal probieren."); } </script> </head> <body> </body></html>

Die while-Anweisung ist eine sogenannte Schleife. Neben der while-Schleife bieten Programmier-sprachen auch andere Schleifen wie die do-while-Schleife oder die for-Schleife an. Alle dieseSchleifen arbeiten jedoch ähnlich: Sie führen einen Anweisungsblock wiederholt aus, und zwar solan-ge eine zu überprüfende Bedingung wahr ist.

Im Zusammenhang mit Schleifen taucht oft ein Programmierfehler auf, der Endlosschleife genanntwird. Eine Endlosschleife ist eine Schleife, die unendlich oft wiederholt wird, weil die zu überprüfendeBedingung immer wahr bleibt. Endlosschleifen machen sich dadurch bemerkbar, dass das Programmscheinbar stehen bleibt und auf Benutzereingaben nicht mehr reagiert.

<html> <head> <title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript"> var passwort = "abc"; var eingabe = prompt("Geben Sie ein Passwort ein.");

while (eingabe != passwort) { eingabe = prompt("Das Passwort ist falsch. Bitte nochmal probieren."); if (eingabe == "ende") { break; } } </script>

Page 11: Allgemeine Grundlagen Der Programmierung

Programmiersprachen

6

</head> <body> </body></html>

Über ein zusätzliches Schlüsselwort wie break ist es darüberhinaus möglich, Schleifen vorzeitig zuverlassen. Die Schleife endet dann also nicht, weil die zu überprüfende Bedingung nicht mehr wahrist, sondern sie endet sofort, wenn die Code-Ausführung auf break trifft.

FunktionenJederzeit aufrufbare Anweisungsblöcke

Den Begriff Anweisungsblock haben Sie bereits im Zusammenhang mit Kontrollstrukturen gehört. EinAnweisungsblock ist in den Programmiersprachen Javascript, C, C++ und Java durch die geschweiftenKlammern { und } begrenzt. Zusammen mit den darin enthaltenen Anweisungen bilden sie einenAnweisungsblock, der beispielsweise dem Schlüsselwort if folgen kann.

Anweisungsblöcken lassen sich auch Namen zuordnen. Über diesen Namen kann ein Anweisungs-block aufgerufen werden. Dadurch wird er ausgeführt. Ein derart aufrufbarer Anweisungsblock wirdFunktion genannt.

<html> <head> <title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript"> function hallo() { alert("Hallo!"); }

hallo(); </script> </head> <body> </body></html>

Obiges Code-Beispiel zeigt, wie Funktionen in Javascript aussehen. Hinter dem Schlüsselwort fun-ction folgt der Name der Funktion. Hinter dem Namen werden gegebenfalls in Klammern Parameterangegeben. Ansonsten bleiben die Klammern leer. Im Funktionsrumpf - also im Anweisungsblock -werden nun alle Anweisungen definiert, die ausgeführt werden sollen, wenn die Funktion aufgerufenwird.

Parameter sind Eingabewerte, die man an eine Funktion weitergeben kann, wenn man sie aufruft,und die intern in der Funktion verarbeitet werden. Nicht jede Funktion benötigt Eingabewerte. DieFunktion im obigen Beispiel zeigt einfach eine Meldung am Bildschirm an, so dass es nicht nötig ist,irgendwelche Parameter an diese Funktion weiterzureichen.

Wenn man auf eine mit function definierte Funktion zugreifen möchte, ruft man sie über denFunktionsnamen auf. Man gibt hierzu den Namen der Funktion an und dahinter in Klammern eventuellzu übergebene Parameter. Nachdem die Funktion hallo keine Parameter erwartet, wird beim Aufrufauch keiner zwischen den Klammern angegeben. Die Klammern sind dennoch wichtig und dürfennicht weggelassen werden, um hallo eindeutig als Funktionsaufruf zu identifizieren und nicht alsVariable.

<html> <head> <title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript">

Page 12: Allgemeine Grundlagen Der Programmierung

Programmiersprachen

7

function add(a, b) { alert(a + b); }

var i = 1, j = 2; add(i, j); </script> </head> <body> </body></html>

Im obigen Javascript-Code wird nun eine Funktion definiert, die zwei Parameter a und b erwartet. Dasheißt, bei Aufruf der Funktion add müssen in Klammern auch zwei Parameter übergeben werden. ImBeispiel sind das die Variablen i und j. Durch den Aufruf der Funktion add und die Übergabe derbeiden Variablen wird innerhalb der Funktion die Summe der übergebenen Werte gebildet. a und bstellen letztendlich nur Platzhalter dar für die Werte, die beim Aufruf der Funktion angegeben werden.

Wenn Sie sich obiges Beispiel genau ansehen, stellen Sie fest, dass unter anderem eine Funktionalert aufgerufen wird. Diese Funktion ist eine in Javascript eingebaute Funktion und steht demProgrammierer in Javascript automatisch zur Verfügung. Mit alert öffnet sich ein kleines Fensterauf dem Bildschirm, das jeweils das anzeigt, was als Parameter der Funktion alert übergeben wurde- im obigen Fall also das Ergebnis der Addition.

Strukturen

DatenblöckeSo wie sich mehrere Anweisungen zu Funktionen zusammenpacken lassen ist es auch möglich, meh-rere Variablen zu einer Struktur zusammenzustellen. Diese Möglichkeit besteht jedoch in der Pro-grammiersprache Javascript nicht, so dass folgendes Code-Beispiel der Programmiersprache C++ ent-nommen ist.

struct adresse { string Vorname; string Nachname; string Strasse; int PLZ; string Ort; };

adresse MeineAdresse;

Durch das Erstellen einer Struktur ist es möglich, Datentypen in seinem Programm zu verwenden, diees noch nicht gibt. Nachdem C++ nicht von Haus aus einen Datentyp für die Speicherung von Adressenzur Verfügung stellt, können Sie dank Strukturen nun diesen Datentyp selber erstellen. Einmal erstelltkönnen Sie wie gewohnt von diesem neuen Datentyp eine Variable anlegen. Im obigen Beispiel ist derName der Variablen MeineAdresse. Und diese Variable kann nun Informationen vom Typ adressespeichern.

Sonstige Bestandteile

Von Klassen und ObjektenDie in diesem Kapitel bekanntgewordenen Bestandteile einer Programmiersprache finden Sie infast jeder Sprache. Darüberhinaus bieten Programmiersprachen teilweise Elemente wie Klassen und

Page 13: Allgemeine Grundlagen Der Programmierung

Programmiersprachen

8

Objekte an. Zu diesen Programmiersprachen gehören beispielsweise Smalltalk, C++ und Java. Es han-delt sich hierbei um objektorientierte Programmiersprachen. In derartigen Programmiersprachen wirdmit Objekten gearbeitet, die eine Programmentwicklung ermöglichen, die näher an der Problembe-schreibung orientiert ist. Durch geringere Abstraktion vom Problem zum Lösungs-Programm lassensich vor allem größere Anwendungen einfacher entwickeln, die durch fehlende Klassen- und Objekt-Unterstützung zu unübersichtlich werden würden.

Objektorientierte Programmiersprachen stellen derzeit den heiligen Graal unter den Programmierspra-chen dar. Sie sind das leistungsfähigste Instrument, mit dem heutzutage Software entwickelt werdenkann. Die meisten großen und erfolgreichen Anwendungen wie zum Beispiel der Internet Explorervon Microsoft oder sämtliche Programme aus Microsoft Office sind objektorientiert programmiert.Dennoch hat auch die Objektorientierung etwas von ihrem Glanz verloren. Galt sie noch vor Jahrenals das Nonplusultra, als die endgültige Lösung aller Probleme in der Software-Entwicklung, so mussman dennoch erkennen, dass sie kein Allheilmittel ist, sondern ebenfalls durchaus verbesserungswür-dig ist. Selbstverständlich entwickeln sich auch Programmiersprachen und Managementmethoden inder Software-Entwicklung weiter, so dass auch hier sicherlich noch nicht aller Tage Abend ist.

Sprach-Entwicklung

Von proprietären Sprachen und offenen StandardsDie Entwicklung der Programmiersprachen verläuft großenteils sehr verflochten. Die heute sehr ver-breiteten Programmiersprachen C, C++ und Java sind sehr ähnlich gestrickt. C trat hierbei zeitlichzuerst auf, wurde dann um objektorientierte Elemente zu C++ ergänzt. Die Entwicklung der Program-miersprache Java Jahre später wurde sehr eng an C++ angelehnt. Javascript wurde gleichzeitig zu Javaentwickelt und hieß ursprünglich ActiveScript. Vor dem ersten Release wurde die Sprache dann anJava angepaßt - sowohl von ihrer Syntax als dann auch vom Namen her.

Die vor allem im Bereich der Windows-Betriebssysteme verbreitete Sprache Visual Basic stammt vonBasic ab. Basic selbst ist ebenfalls wie C eine recht alte Sprache, die auch unter dem Vorgänger vonWindows, MS-DOS, als qbasic vertreten war. Auch VBScript, eine Konkurrenzsprache zu Javascript,ist sehr eng mit Visual Basic verwandt. Heutzutage ist Basic in all seinen Dialekten vor allem eineProgrammiersprache, die stark von Microsoft unterstützt und weiterentwickelt wird und daher vorran-gig auf den Betriebssystemen von Microsoft Einsatz findet.

Die allermeisten Sprachen gehören der Allgemeinheit, um es etwas salopp auszudrücken. Sie wer-den von Programmierern weltweit weiterentwickelt, was spätestens seit dem Internet kein Problemmehr darstellt. Die Standardisierung der Weiterentwicklungen übernehmen internationale Gremien,in denen meist Vertreter führender Softwarefirmen sitzen. Die prominenten Gründerväter der Pro-grammiersprachen sprechen innerhalb der Weiterentwicklung und Standardisierungsgremien natür-lich häufig auch ein paar wichtige Worte mit.

Die wohl bekannteste Programmiersprache, die einer Firma gehört und nicht von internationalen Gre-mien weiterentwickelt wird, ist Java. Java ist eine proprietäre Sprache und gehört der Firma Sun Micro-systems. Wer Java benutzen will, muss die Lizenzbestimmungen zu Java akzeptieren. Eine unabhängi-ge Weiterentwicklung der Programmiersprache ist hierbei verboten. Im Januar 2001 endete ein mehr-jähriger Gerichtsprozess zwischen Sun und Microsoft, in dem Sun Microsoft vorwarf, sich nicht an dieLizenzbestimmungen gehalten zu haben, sondern auf eigenständige Weise die ProgrammierspracheJava verändert zu haben. Seit Januar 2001 wird daher Java von Microsoft nicht mehr unterstützt.

Compiler und Interpreter

Vom Quellcode zur ProgrammausführungWenn Sie wie in den obigen Beispielen kleine Programme schreiben, arbeiten Sie als Programmiererimmer mit dem Quellcode. Der Quellcode ist der für den Menschen lesbare Programmablauf. WährendSie und ich diesen Quellcode recht gut verstehen, kann der Computer damit überhaupt nichts anfangen.

Page 14: Allgemeine Grundlagen Der Programmierung

Programmiersprachen

9

Das ist insofern von Bedeutung, als dass Sie ja möchten, dass der Computer Ihr Programm ausführt.Der Computer versteht aber nur Maschinencode. Das heißt, irgendjemand muss den Quellcode desProgramms in Maschinencode umwandeln.

Zum Umwandeln von Quellcode in Maschinencode werden Programme verwendet, die Compiler heis-sen. Je nach verwendeter Programmiersprache und Computersystem brauchen Sie einen anderen Com-piler. Wenn Ihr Quellcode in der Programmiersprache C++ geschrieben ist und Sie das Programmbeispielsweise auf einem Computer mit dem Intel-Pentium-Chip ausführen lassen möchten, brauchenSie einen Compiler, der C++-Quellcode in Maschinencode für den Intel-Chip umwandeln kann. SollIhr C++-Quellcode dagegeben auf einem Computer mit einem PowerPC-Chip laufen, brauchen Sieeinen Compiler, der C++ in Maschinencode für den PowerPC umwandelt. Compiler müssen also aufder einen Seite die Sprache des Quellcodes beherrschen, auf der anderen Seite auch den Maschinen-code des Zielsystems.

Neben Compilern gibt es noch sogenannte Interpreter. Wenn Sie Javascript-Beispiele ausführen, stel-len Sie fest, dass Sie nirgendwo Ihren Quellcode in Maschinencode umwandeln. Der PC verstehtIhren Quellcode scheinbar automatisch. Dies funktioniert nur deswegen, weil das Programm, das IhrenQuellcode ausführt, zuerst einen Interpreter startet, der Ihren Quellcode analysiert. Nach dieser Ana-lyse weiß dann das Programm, was Sie eigentlich in Ihrem Quellcode machen wollen, und führt dieentsprechenden Funktionen aus. Da in den modernen Browsern heutzutage ein Javascript-Interpre-ter integriert ist, können Sie normalerweise ohne Probleme sämtliche Javascript-Beispiele in IhremBrowser ausführen.

Quellcodes, die mit Compilern in Maschinencode umgewandelt werden, müssen diese Umwandlungnur einmal vornehmen. Danach liegt eine ausführbare Datei vor, die Sie - beispielsweise durch Dop-pelklick wie in Windows - jedesmal sofort starten können. Man spricht auch von nativen Anwendun-gen. Sie brauchen den Quellcode nicht mehr, da in der Datei bereits der vollständige Maschinencodevorliegt. Und das ist das einzige, was der PC benötigt.

Quellcode wie beispielsweise der in Javascript muss jedesmal, wenn er ausgeführt werden soll, neuvom Programm analysiert werden. Hier wird nirgendwo Maschinencode erstellt oder gar für spätereweitere Programmausführungen gespeichert. Dadurch, dass jedesmal eine neue Analyse notwendigist, sind Programme, die interpretiert werden, in der Ausführung langsamer als Programme, die bereitsals Maschinencode vorliegen. Hier fällt eine Analyse weg, der Computer kann den Maschinencodesofort ausführen.

Die Programmiersprache Java nimmt hier eine Sonderstellung ein. Quellcode in Java wird kompiliert,jedoch nicht für ein ganz bestimmtes Zielsystem wie einen Intel-Pentium-Chip oder einen Power-PC-Chip, sondern für eine virtuelle Maschine. Diese virtuelle Maschine ist letztendlich ein Compu-ter-Programm, das den kompilierten und virtuellen Maschinencode interpretiert. Durch die Umwand-lung von Java-Quellcode in virtuellen Maschinencode und durch die Interpretierung des virtuellenMaschinencodes kann eine höhere Ausführungsgeschwindigkeit erreicht werden als bei rein interpre-tierenden Sprachen. Die Ausführungsgeschwindigkeiten von rein kompilierten Programmiersprachenim Vergleich zu Java sind dennoch um das zehn- bis zwanzigfache schneller - ganz grob über denDaumen gepeilt. Durch die Kompilierung des Quellcodes für eine virtuelle Maschine ist Java abereine Sprache mit größerer Portabilität. Während beispielsweise C++-Programme entweder für einenIntel-Pentium-Chip oder aber für einen PowerPC-Chip kompiliert werden, laufen Java-Programmeauf allen Computer-Systemen - immer vorausgesetzt, ein Programm für die Interpretierung des vir-tuellen Maschinencodes existiert. Java-Programme tauschen sogesehen Ausführungsgeschwindigkeitgegen Portabilität ein.

Aufgaben

Übung macht den Meister1. Entwickeln Sie ein Programm in Javascript, das den Anwender zur Eingabe eines Passworts auf-

fordert. Wird das Passwort dreimal hintereinander falsch eingegeben, soll keine weitere Eingabe-aufforderung mehr erscheinen.

Page 15: Allgemeine Grundlagen Der Programmierung

Programmiersprachen

10

2. Entwickeln Sie ein Programm in Javascript, das den Anwender auffordert, zwei Zahlen einzugeben.Addieren Sie die beiden Zahlen und geben Sie das Ergebnis auf den Bildschirm aus.

3. Entwickeln Sie ein Programm in Javascript, das den Anwender auffordert, zwei Zahlen einzuge-ben und danach eines der vier Zeichen +, -, / und *. Je nach eingegebenem Zeichen sollen die bei-den Zahlen addiert, subtrahiert, dividiert oder multipliziert werden. Das Ergebnis der jeweiligenRechenart soll auf den Bildschirm ausgegeben werden. Entwickeln Sie keine eigenen Funktionenzur Lösung der Aufgabe.

4. Entwickeln Sie den Javascript-Taschenrechner der obigen Aufgabe diesmal unter Verwendung vonFunktionen. Dabei soll für jede der vier Rechenarten eine andere Funktion aufgerufen werden, diedie jeweilige Rechenoperation durchführt und dann das Ergebnis auf den Bildschirm ausgibt.

Page 16: Allgemeine Grundlagen Der Programmierung

11

Kapitel 2. Zahlensysteme

Allgemeines

Eigenheiten von Zahlensystemen

Für den Nicht-Programmierer ist oft gar nicht bewußt, dass es verschiedene Zahlensysteme gibt unddass das im Alltag verwendete Dezimalsystem nur eines von unendlich vielen ist. Zahlensystemewerden über Zeichenvorrat und Stellenwert definiert. Der Zeichenvorrat repräsentiert die zugelassenenZeichen im Zahlensystem. Das sind im Dezimalsystem die Ziffern 0, 1, 2, 3, 4, 5, 6, 7, 8 und 9. DerStellenwert legt fest, welche Basiszahl mit der Stelle einer Ziffer potenziert wird. Die Basiszahl imDezimalsystem ist 10.

Der Wert der drei Ziffern 456 wird im Dezimalsystem also genaugenommen wie folgt berechnet: DieStelle ganz rechts ist die 0. Die Stelle links daneben, auf der die Ziffer 5 steht, ist die 1. Die Stelle ganzlinks ist die 2. Weitere Stellen würden mit linear aufsteigenden Zahlen beschrieben werden. Wie Siebereits wissen, wird mit der Stellenbeschreibung jeweils die Basiszahl potenziert. Die Stelle 0 wirdalso zu 100, die Stelle 1 wird zu 101 und die Stelle 2 wird zu 102. Das jeweilige Ergebnis wird mit derZiffer an der jeweiligen Stelle multipliziert. An der Stelle 0 steht im Beispiel die Ziffer 6, an der Stelle1 die Ziffer 5 und an der Stelle 2 die Ziffer 4. Die gesamte Rechnung heisst also 6*100+5*101+4*102.Das ergibt 6*1+5*10+4*100, was wiederum 6+50+400 ergibt und zur Lösung 456 führt.

Wenn Sie eine Zahl wie 456 im Dezimalsystem sehen, brauchen Sie natürlich nicht jedesmal dieBerechnung ausführen. Sie wissen sofort, was die Zahl bedeutet, weil Sie es gewohnt sind, im Dezi-malsystem zu arbeiten. Sie müssen sich aber die Regeln zum Berechnen des Wertes einer Zahl verge-genwärtigen, wenn Sie Zahlen aus anderen Zahlensystemen vor sich haben. Oder können Sie sofortsagen, was die Hexadezimalzahl FA oder die Binärzahl 10011 für Werte darstellen?

Zahlensysteme und der Computer

Computer kennen keine Buchstaben

Wieso müssen Sie sich eigentlich mit Zahlensystemen beschäftigen? Sie sind doch Programmierer undkein Mathematiker. Leider haben Sie es als Programmierer mit einer Maschine zu tun, die ausschließ-lich mit Zahlen arbeitet. Computer sind wahre Zahlenakrobate. Wenn Sie dem Computer irgendwasdirekt sagen wollen, dann müssen Sie sich in Zahlen ausdrücken. Das nächste Problem ist, dass derComputer zwar grundsätzlich Zahlen versteht, es aber vorzieht, in anderen Zahlensystemen zu arbeitenals Sie. Während Sie im Alltag mit dem Dezimalsystem gut zurechtkommen, verwendet Ihr Computeram liebsten das Binärsystem. Und damit es nicht zu einfach wird, lassen sich Zahlen im Binärsystemleider nicht allzu einfach in Zahlen des Dezimalsystems umwandeln. Nachdem das Binärsystem fürmenschliche Belange äußerst unangenehm zu handhaben ist, verwenden Programmierer lieber dasHexadezimalsystem. Denn vom Binärsystem ins Hexadezimalsystem sind es nur ein paar Schritte,und die Handhabung von Hexadezimalzahlen fällt doch wesentlich einfacher als die von Binärzahlen.

Beachten Sie, dass moderne Programmiersprachen normalerweise ohne Probleme die Angabe vonDezimalzahlen ermöglichen, wenn an irgendeiner Stelle im Programm Zahlen angegeben werden müs-sen. Sie sind also als Programmierer grundsätzlich nicht gezwungen, sich mit Binär- oder Hexadezi-malzahlen herumzuschlagen. Dennoch kann es in vielen Fällen hilfreich sein zu wissen, wie Zahlenim Binär- und Hexadezimalsystem aussehen und gebildet werden.

Page 17: Allgemeine Grundlagen Der Programmierung

Zahlensysteme

12

Das Binärsystem

Nullen und Einser

Vielleicht kennen Sie den Spruch, dass Computer nur Nullen und Einsen kennen. Nullen und Ein-ser sind die einzigen beiden gültigen Zeichen im Binärsystem. Der Zeichenvorrat des Binärsystemsbesteht also aus 0 und 1. Wenn Sie nun erfahren, dass der Stellenwert im Binärsystem 2 ist, haben Siealle Informationen, die Sie brauchen, um den Wert von Binärzahlen zu errechnen.

Sehen Sie sich zum Beispiel die Binärzahl 10011 ein. An der Stelle 0 steht eine 1, an der Stelle 1ebenfalls eine 1, an der Stelle 2 eine 0, an der Stelle 3 auch eine 0 und an der Stelle 4 wiederum eine1. Stellen werden immer von rechts nach links beginnend bei Null hochgezählt. Da der Stellenwertim Binärsystem 2 ist, sieht die Berechnung wie folgt aus: 1*20+1*21+0*22+0*23+1*24. Das ergibt1*1+1*2+0*4+0*8+1*16, was wiederum 1+2+0+0+16 ergibt. Die Lösung lautet also 19. Die Binär-zahl 10011 stellt im Dezimalsystem den Wert 19 dar.

Wie gelangt man nun von der Dezimalzahl 19 zur entsprechenden Binärdarstellung? Dividieren Siedie Dezimalzahl durch den Stellenwert des Binärsystems, nämlich 2, und notieren Sie den Restwert.Divideren Sie das Ergebnis wiederum durch 2 und notieren Sie wieder den Restwert. Irgendwanngelangen Sie bei Null an. Sie erhalten nun die Binärzahl, wenn Sie die erhaltenen Restwerte in eineReihe stellen. Beispiel gefällig?

19/2=9 Rest 1. 9/2=4 Rest 1. 4/2=2 Rest 0. 2/2=1 Rest 0. 1/2=0 Rest 1. Schreiben Sie nun die Restwertevon rechts nach links in eine Reihe und Sie erhalten 10011.

Das Hexadezimalsystem

Zahlen und ein paar Buchstaben

Im Hexadezimalsystem steht folgender Zeichenvorrat zur Verfügung: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B,C, D, E und F. Während das Binärsystem im Gegensatz zum Dezimalsystem weniger Informations-zustände an einer Stelle speichern kann - nämlich nur zwei -, können im Hexadezimalsystem mehrInformationszustände gespeichert werden - nämlich 16. Die ersten zehn Zeichen sind mit denen imDezimalsystem identisch. Für den Dezimalwert 10 benötigen Sie im Dezimalsystem aber zwei Stel-len. Im Hexadezimalsystem können Sie diesen Wert an einer Stelle durch das Zeichen A ausdrücken.Erst ab Zahlen oberhalb des Dezimalwerts 15, der im Hexadezimalsystem dem Zeichen F entspricht,wird eine zweite Stelle benötigt.

Wie sieht nun die Umwandlung einer Hexadezimalzahl, zum Beispiel FA, ins Dezimalsystem aus?Dazu benötigen Sie neben dem Zeichenvorrat noch den Stellenwert. Der ist im Hexadezimalsystem16. Und schon können Sie loslegen. An der Stelle 0 steht das Zeichen A, an der Stelle 1 das ZeichenF. Die Berechnung sieht also wie folgt aus: A*160+F*161. Nachdem das Dezimalsystem keine Buch-staben verwendet, werden die Zeichen aus dem Hexadezimalsystem einfach durch die Werte aus demDezimalsystem ersetzt. Die neue Rechnung heißt also: 10*160+15*161. Daraus folgt 10*1+15*16,was als Ergebnis 250 ergibt.

Die Umrechnung einer Dezimalzahl in eine Hexadezimalzahl erfolgt nach demselben Schema wiebei Binärzahlen. Sie dividieren die Dezimalzahl durch den Stellenwert, also 16, und notieren denRest. Dann wiederholen Sie den Schritt, indem Sie das Ergebnis der eben durchgeführten Berechnungwiederum durch 16 dividieren. Dies wiederholt sich, bis Sie bei Null angelangt sind. Im letzten Schrittwandeln Sie dann gegebenenfalls zweistellige Restwerte in die Buchstaben aus dem Zeichenvorratdes Hexadezimalsystems um.

250/16=15 Rest 10. 15/16=0 Rest 15. 10 entspricht A, 15 entspricht F. In der richtigen Reihenfolge -nämlich von rechts nach links - ergibt dies die Hexadezimalzahl FA.

Page 18: Allgemeine Grundlagen Der Programmierung

Zahlensysteme

13

Vom Binärsystem zum Hexadezimalsystemund zurück

ZahlenzauberSie kennen nun das Binärsystem und das Hexadezimalsystem. Wenn Sie sich erinnern, habe ich Ihnendas Hexadezimalsystem verkauft als das System, in das sich Binärzahlen besonders leicht transferierenlassen. Inwiefern läßt sich aber die Binärzahl 11101010 besonders leicht in die Hexadezimalzahl EAumwandeln?

Der Trick ist, dass jeweils vier Stellen im Binärsystem eine Stelle im Hexadezimalsystem darstellen.Das heißt, die Binärzahl 0001 entspricht im Hexadezimalsystem 1, 0010 entspricht 2, 0011 entspricht3 bis hin zu 1110 entspricht E und 1111 entspricht F. Für die nächsthöhere Zahl brauchen Sie sowohlim Binärsystem als auch im Hexadezimalsystem eine neue Stelle. Wenn Sie sich nun die Binärzahl11101010 ansehen, besteht diese aus acht Stellen. Nachdem jeweils vier Stellen im Binärsystem eineStelle im Hexadezimalsystem darstellen, wissen Sie bereits, dass Sie genau zwei Stellen brauchen.Schauen wir uns die ersten vier Stellen an: 1110. Per Umrechnung ins Dezimalsystem kommen Siezum Wert 14 (diese Umrechnungen brauchen Sie mit ein wenig Erfahrung nicht mehr durchführen, daSie den Wert sofort erkennen). 14 ist im Hexadezimalsystem E. Damit steht das erste Zeichen schonmal fest. Die nächsten vier Binärziffern sind 1010. Per Umrechnung ins Dezimalsystem gelangenSie zum Wert 10. 10 entspricht im Hexadezimalsystem dem Zeichen A. Damit ist die Umrechnungkomplett: Die Binärzahl 11101010 entspricht im Hexadezimalsystem EA.

Nachdem Sie nun den Trick raushaben, fällt auch die Umrechnung einer Hexadezimalzahl ins Binär-system nicht mehr schwer. Sie wandeln einfach jede Stelle der Hexadezimalzahl in vier Stellen einerBinärzahl um. Nachdem die Hexadezimalzahl EA aus zwei Stellen besteht, muss die entsprechendeBinärzahl aus acht Stellen bestehen. An der Stelle ganz links steht das Zeichen E, was dem Dezimal-wert 14 entspricht. Per Umrechnung gelangen Sie zur Darstellung 1110. Das zweite Zeichen ist A, wasdem Dezimalwert 10 entspricht. Der Dezimalwert 10 sieht in Binärform wie folgt aus: 1010. Damitist klar, dass die Hexadezimalzahl EA in Binärform 11101010 lautet.

Zahlensysteme in der Praxis

Beim Zahlarzt in der PraxisStandardmäßig werden Zahlen, die Sie in Quellcodes zur Entwicklung von Computer-Programmenangeben, als Dezimalzahlen geschrieben. Über spezielle Kennzeichnungen können Sie jedoch auchHexadezimalzahlen angeben. Binärzahlen selber werden seltener unterstützt, nachdem die Schreib-weise aus Nullen und Einsen sehr fehleranfällig ist und mit Hexadezimalzahlen eine bessere Lösungzur Verfügung steht.

int i = 0x14;

Obiges Code-Beispiel ist in der Programmiersprache C geschrieben. Einer Variablen i vom Typ intwird die Hexadezimalzahl 14 zugewiesen. Damit der Compiler erkennt, dass es sich um eine Hexa-dezimalzahl handelt, wird in C das Kürzel 0x dem Wert vorangestellt.

Programmiersprachen wie C stellen noch eine andere Notation zur Verfügung.

int i = 014;

Durch das Voranstellen von 0 wird die Zahl im Oktalsystem notiert. Das Oktalsystem besitzt denZeichenvorrat 0, 1, 2, 3, 4, 5, 6 und 7 und den Stellenwert 8. Es hat ähnliche Vorteile wie das Hexade-zimalsystem: Jeweils drei Binärstellen können in eine Oktalstelle umgewandet werden (beim Hexa-dezimalsystem vier Binärstellen in eine Hexadezimalstelle). Die Bedeutung in der Praxis ist jedochsehr gering.

Page 19: Allgemeine Grundlagen Der Programmierung

Zahlensysteme

14

Wie Sie bereits aus Kapitel 1, Programmiersprachen wissen, stellen Programmiersprachen unter ande-rem bitweise Operatoren zur Verfügung. Mit diesen Operatoren können Sie einzelne Bits bearbeiten.Bits sind hierbei Informationen, die lediglich zwei Zustände annehmen können: Also wahr oder falsch,gesetzt oder nicht gesetzt, 1 oder 0. Binärzahlen eignen sich hervorragend zur Darstellung von Bits.

<html> <head> <title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript"> var i = 0xC, j = 0x5;

alert(i & j); </script> </head> <body> </body></html>

Im obigen Javascript-Code werden zwei Variablen namens i und j definiert. Den Variablen werdendie Hexadezimalzahlen C und 5 zugewiesen. Die Darstellung im Binärsystem der beiden Zahlen ist1100 und 0101. Die zwei Variablen werden mit dem &-Operator verknüpft, der UND-Operator genanntwird. Dieser bitweise Operator arbeitet wie folgt: Bits an den gleichen Stellen werden miteinanderverglichen. Sind beide Bits gesetzt - ist also an beiden Stellen die 1 vorhanden - wird das entsprechendeBit im Ergebnis ebenfalls auf 1 gesetzt.

Sie müssen nun lediglich Bits an den jeweils gleichen Stellen der beiden Variablen vergleichen: Ander Stelle 0 der Variablen i befindet sich eine 0, in der Variablen j eine 1. Die Stelle 0 im Ergebniswird also auf 0 gesetzt. An der Stelle 1 in der Variablen i befindet sich wieder eine 0, in der Variablenj auch. Die Stelle 1 im Ergebnis wird also auf 0 gesetzt. An der Stelle 2 in der Variablen i befindetsich eine 1, in der Variablen j ebenfalls. Daher wird die Stelle 2 im Ergebnis auf 1 gesetzt. Die Stelle3 ist nur in einer der beiden Variablen gesetzt, also wird im Ergebnis an der Stelle 3 eine 0 stehen. DasErgebnis des bitweisen Operators sieht also wie folgt aus: 0100. Dies entspricht 4 im Hexadezimal-und auch im Dezimalsystem.

<html> <head> <title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript"> var i = 0xC, j = 0x5;

alert(i | j); </script> </head> <body> </body></html>

Ein anderer bitweiser Operator ist |, genannt ODER-Operator. Hier gilt die Regel: Im Ergebnis istdann ein Bit gesetzt, wenn mindestens ein Bit in einem Operand gesetzt ist. Im Gegensatz zum &-Operator müssen nicht beide Bits gesetzt sein. Um zum Ergebnis zu gelangen, müssen wieder einzelneBits miteinander verglichen werden: An der Stelle 0 befindet sich in der Variablen i eine 0, in derVariablen j eine 1. Daher wird im Ergebnis an der Stelle 0 eine 1 stehen. An der Stelle 1 befindet sichin der Variablen i eine 0, in der Variablen j ebenfalls. Die Stelle 1 im Ergebnis trägt daher auch eine0. An den Stellen 2 und 3 der Variablen i und j befindet sich jedesmal mindestens eine 1, so dassauch im Ergebnis die Stellen 2 und 3 auf 1 gesetzt werden. Das Resultat ist also die Binärzahl 1101,die im Hexadezimalsystem D und im Dezimalsystem 13 entspricht.

<html> <head>

Page 20: Allgemeine Grundlagen Der Programmierung

Zahlensysteme

15

<title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript"> var i = 0xC, j = 0x5;

alert(i ^ j); </script> </head> <body> </body></html>

Der ^-Operator wird EXKLUSIVES-ODER genannt. Im Ergebnis ist nur dann ein Bit auf 1 gesetzt,wenn auch nur genau ein Bit in den beiden Operanden auf 1 gesetzt ist. Sind die Bits in beiden Ope-randen auf 1 gesetzt, so steht im Ergebnis an gleicher Stelle eine 0.

<html> <head> <title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript"> var i = 0xC;

alert(~i); </script> </head> <body> </body></html>

Ein recht einfacher bitweiser Operator ist ~. Im Gegensatz zu den anderen Operatoren benötigt erlediglich einen einzigen Operanden, der hinter ~ angegeben wird. Dieser Operator dreht die Bits ein-fach um: Aus auf 1 gesetzten Bits werden auf 0 gesetzte Bits, aus auf 0 gesetzten Bits werden auf 1gesetzte Bits. Das heißt, aus 1100 wird 0011, was der Hexadezimalzahl 3 entspricht (die auch gleich-zeitig Dezimalzahl ist). Der bitweise Operator ~ wird NICHT-Operator genannt.

Sollte Ihr Browser bei der Ausführung des Beispiels anstelle der 3 eine negative Zahl als Ergebnisanzeigen, so ist dies völlig korrekt. Unterschiedliche Ergebnisse hängen von der Bandbreite der Varia-blen i ab. Wundern Sie sich nicht, sondern gehen Sie von obiger Beschreibung aus und ignorierenSie gegebenenfalls ein negatives Ergebnis.

Aufgaben

Übung macht den Meister1. Wandeln Sie die Dezimalzahl 40019 mit Stift und Papier in die entsprechende Hexadezimalzahl

und in die entsprechende Binärzahl um.

2. Wandeln Sie die Oktalzahl 143215 mit Stift und Papier in die entsprechende Hexadezimalzahl undin die entsprechende Binärzahl um.

3. Schreiben Sie ein Programm in Javascript, das die beiden Werte aus den ersten zwei Aufgaben mitden bitweisen Operatoren &, | und ^ verknüpft. Sagen Sie die Ergebnisse der bitweisen Verknüp-fungen als Dezimalwerte voraus, bevor Sie das Programm ausführen.

4. Für Experten: Schreiben Sie ein Programm in Javascript, das vom Anwender eine Dezimalzahlentgegennimmt und diese in eine Hexadezimalzahl umrechnet. Sie benötigen für die Realisierungdes Programms den %-Operator. Dieser Operator dividiert zwei Werte und gibt als Ergebnis denganzzahligen Restwert zurück.

Page 21: Allgemeine Grundlagen Der Programmierung

Zahlensysteme

16

Tipp

Zur Realisierung des Programms benötigen Sie eine Schleife, die wiederholt eine Divisionausführt und die Restwerte zur Hexadezimalzahl zusammenstellt. Vergessen Sie nicht,zweistellige Restwerte in Buchstaben umzuwandeln.

Page 22: Allgemeine Grundlagen Der Programmierung

17

Kapitel 3. Rechnerarchitektur

Allgemeines

Binärsystem auf physikalischer EbeneAls Programmierer beschäftigen Sie sich hauptsächlich mit Software. Sie erstellen Programmabläu-fe, in denen Informationen verarbeitet werden. Tatsache ist, dass für diese InformationsverarbeitungSoftware alleine nicht ausreicht. Man benötigt eine physikalische Maschine, auf der die Software lau-fen kann: Die Hardware.

Die Hardware arbeitet wie eine ganze Menge anderer Geräte auch mit Strom. Während beispielsweiseLampen Strom ausschließlich als Energiequelle verwenden, bedient sich der Computer des Stromsauch als Informationsträger. Er unterscheidet hierbei zwei Zustände: Strom und kein Strom.

An dieser Stelle sollte Ihnen sofort das Binärsystem in den Sinn kommen. Strom und kein Strom, anund aus, 1 und 0. Sie haben bereits gesehen, dass man mit dem Binärsystem eine ganze Menge machenkann. Durch bitweise Operatoren können Zahlen verändert werden, sprich Informationen verarbeitetwerden. Das ist nur deswegen möglich, weil es eben physikalisch ein Äquivalent zu den Zahlenspie-lereien gibt. Durch die Unterscheidung zwischen Strom und kein Strom kann das Binärsystem abge-bildet werden, und damit ist der Grundstein für mathematische Berechnungen gelegt.

Digitale Grundschaltungen

Spielen mit StromDass der Zustand "kein Strom" den Wert 0 im Binärsystem bedeuten kann und der Zustand "Strom"den Wert 1 ist zwar ganz nett, aber wie kann man nun damit zu rechnen anfangen? Bis hin zum richti-gen Rechnen ist es noch ein etwas längerer Weg. Und er beginnt mit den digitalen Grundschaltungen.

Die UND-Schaltung ist ein Stromkreis mit einer Batterie, einer Lampe und zwei Schaltern A und B,die in Serie geschaltet sind. Dieser Stromkreis heißt UND-Schaltung, weil die Lampe nur dann brennt,wenn der Schalter A und der Schalter B geschlossen ist. Ist auch nur einer der beiden Schalter geöffnet(oder beide gleichzeitig), brennt die Lampe nicht - der Stromkreis ist unterbrochen. Die Logik desSchaltkreises ist recht einfach zu verstehen. Er wird nun in ein Modul gepackt, den UND-Schalter.Dieses Modul hat zwei Eingänge und einen Ausgang. Der Ausgang liefert nur dann Strom, wenn beideEingänge Strom liefern.

Erinnern Sie sich noch an die bitweisen Operatoren? An den &-Operator in Javascript? Dieser Operatorwird auf der Hardware-Ebene genau durch die UND-Schaltung ausgeführt: Ein Bit im Ergebnis istdann gesetzt, wenn in beiden Variablen die Bits gesetzt sind. Das entspricht der UND-Schaltung.

Die ODER-Schaltung funktioniert so, dass die Lampe brennt, wenn mindestens ein Schalter im Strom-kreis geschlossen ist. Die beiden Schalter A und B sind dazu parallel geschaltet. Der Stromkreis istalso geschlossen, wenn auch nur ein Schalter geschlossen ist. Diese Logik wird nun ebenfalls in ein

Page 23: Allgemeine Grundlagen Der Programmierung

Rechnerarchitektur

18

Modul gepackt, das ODER-Schalter genannt wird. Der Ausgang dieses Moduls liefert dann Strom,wenn mindestens einer der zwei Eingänge Strom liefert.

Diese ODER-Schaltung ist äquivalent zum |-Operator. Vergleichen Sie die Arbeitsweise des Opera-tors mit der Schaltung: Wenn mindestens ein Bit gesetzt ist, ist im Ergebnis an gleicher Stelle auchdas Bit gesetzt.

Ein Schaltkreis, in dem die Lampe leuchtet, wenn der Schalter nicht geschlossen ist, nennt manNICHT-Schaltung. Technisch besteht dieser Schaltkreis genaugenommen aus zwei Schaltkreisen,wobei sich der Schalter im ersten und die Lampe im zweiten Schaltkreis befindet. Beide Schaltkrei-se sind über ein Relais, eine Art Magnet, verbunden. Die Logik dieses Schaltkreises wird in einenNICHT-Schalter gepackt, der einen Ein- und einen Ausgang besitzt. Ist der Eingang auf Strom gesetzt,ist der Ausgang ohne Strom - und andersrum.

Der NICHT-Schalter entspricht dem bitweisen Operator ~.

Die EXKLUSIVE-ODER-Schaltung, der der bitweise Operator ^ entspricht, macht die Schaltkreisekomplett.

Die Technik, die in den Schaltern steckt, besteht natürlich in Wirklichkeit nicht aus Batterien undLampen, sondern aus Transistoren. Es handelt sich hierbei um einen der wichtigsten Bausteine über-haupt, die in der Prozessortechnologie eingesetzt werden. So ist die Anzahl der Transistoren, die zumBeispiel auf einem Chip untergebracht sind, ein Leistungsmerkmal. Dabei gilt im Allgemeinen: Jemehr Transistoren, umso leistungsfähiger. Während zum Beispiel der Pentium III von Intel aus 28Millionen Transistoren besteht, sind auf dem Nachfolgeprozessor Pentium 4 mehr als 42 MillionenTransistoren untergebracht.

Der Halbaddierer

1 + 1 = 10

So simpel die digitalen Grundschaltungen scheinen - es lassen sich durch Kombination der Modulegrößere Schaltungen erstellen, die erstaunliches beherrschen. Die Kombination der Schaltungen siehthierbei so aus, dass Ein- und Ausgänge der UND-, ODER- und NICHT-Schalter miteinander verknüpftwerden.

Page 24: Allgemeine Grundlagen Der Programmierung

Rechnerarchitektur

19

Der Halbaddierer ist ein Baustein, der aus zwei NICHT-Schaltern, drei UND-Schaltern und einemODER-Schalter besteht. Das fertige Modul hat zwei Eingänge A und B und zwei Ausgänge S undÜ. Wenn ein Eingang gesetzt wird, wird der Ausgang S auch gesetzt. Wenn beide Eingänge gesetztsind, wird lediglich Ü gesetzt.

Wenn Sie sich wundern, was das soll - sie haben soeben einen Baustein kennengelernt, der eine Addi-tion mit den Zahlen 0 und 1 durchführen kann. Die Zahl 1 entspricht dabei einem gesetzten Eingang,die Zahl 0 einem nicht gesetzten. Die Addition wird hierbei im Binärsystem durchgeführt.

Die Ausgänge heißen deswegen S und Ü, weil S für Summe und Ü für Überlauf steht. Da nach einerAddition von 1 und 1 der Wert 2 im Binärsystem nicht durch ein einziges Zeichen ausgedrückt wer-den kann, sondern auf eine zweite Stelle zurückgegriffen werden muss, spricht man davon, dass einÜberlauf stattfindet.

Der Volladdierer

1 + 1 + 1 = 11

So wie Sie aus den digitalen Grundschaltungen einen Halbaddierer aufgebaut haben, lassen sich mitHalbaddierern weitere Schalter aufbauen. Für einen Volladdierer benötigen Sie zwei Halbaddierer undeinen ODER-Schalter. Der Volladdierer hat im Gegensatz zum Halbaddierer drei Eingänge A, B undC, ansonsten aber auch nur die beiden Ausgänge S und Ü.

Der Volladdierer arbeitet wie folgt: Ist lediglich einer der drei Eingänge gesetzt, ist auch nur S gesetzt.Sind genau zwei Eingänge gesetzt, ist Ü gesetzt. Sind alle drei Eingänge gesetzt, sind S und Ü gesetzt.Der Volladdierer stellt also eine Schaltung dar, die drei binäre Zahlen addieren kann.

Addition beliebiger Binärzahle

Addieren wie ein König

Sie werden es wahrscheinlich schon vermutet haben: Durch die Kombination von mehreren Vollad-dierern lassen sich weitere Schaltungen erstellen. Mit Volladdierern können Sie bereits beliebig großeBinärzahlen addieren. Wieviel Volladdierer Sie benötigen hängt hierbei ganz alleine von der Größeder Binärzahlen ab, die Sie addieren möchten.

Page 25: Allgemeine Grundlagen Der Programmierung

Rechnerarchitektur

20

Für die Addition von Binärzahlen, die aus jeweils vier Stellen bestehen, brauchen Sie einen Halbad-dierer und drei Volladdierer. Durch Kombination dieser Schalter ist es bereits möglich, im Binärsy-stem Zahlen zwischen 0000 und 1111 zu addieren (entspricht 0 und 15 im Dezimalsystem). MüssenSie größere Zahlen addieren, verwenden Sie einfach mehr Volladdierer.

Akku, ALU und Rechenwerk

Von digitalen Grundschaltungen zum RechenwerkDurch Kombination von digitalen Grundschaltungen können Schalter erstellt werden, die wiederummiteinander kombiniert in größere Module gesteckt werden, die wiederum in noch größere Modulegepackt werden können. Das Zusammenstellen in Module ist ein ganz wichtiger Prozess, verringerter doch wesentlich die Komplexität des gesamten Gebildes. Dieser Prozess gilt auch für die Softwa-re-Entwicklung, in der Anweisungen zu Funktionen und Funktionen zu Bibliotheken zusammenge-packt werden.

Packt man sehr viele Schalter zusammen, erhält man irgendwann ein Rechenwerk. Das Rechenwerkist der Bestandteil eines Prozessors, der für das Rechnen zuständig ist. Das Rechenwerk enthält letzt-endlich zwei wesentliche Elemente: Akku und ALU. Der Akku ist eine Art Speicherelement. Die ALUist die Arithmetical Logical Unit und führt die eigentlichen Berechnungen aus. Die ALU kann selberintern eine Zahl speichern. Da für Addition und Subtraktion jedoch zwei Zahlen notwendig sind, wirddie zweite Zahl jeweils aus dem Akku gelesen. Hat die ALU die Berechnung durchgeführt, wird dasErgebnis wieder im Akku gespeichert.

Der Akku selber ist über einen Datenbus mit einem Speicher verbunden. In diesem Speicher liegenzum Beispiel eine ganze Menge Zahlen, die addiert werden sollen. Über den Datenbus werden dieZahlen an das Rechenwerk weitergegeben. Die ALU führt mit Hilfe des Akkus die Rechenoperationdurch und speichert das Ergebnis wieder im Akku. Damit im Akku Platz für die nächste Zahl aus demSpeicher ist, wird über den Datenbus aus dem Akku das Ergebnis in den Speicher übertragen, damites nicht verloren geht. Danach kann aus dem Speicher über den Datenbus die nächste Zahl an dasRechenwerk weitergegeben werden. Die Verbindung zwischen Rechenwerk und Speicher erfolgt alsoüber einen Datenbus.

Prozessor

Struktur der CPUDer Kern des PCs, der Prozessor, besteht aus dem Rechenwerk und dem Befehlswerk. Während imRechenwerk mit Akku und ALU Berechnungen durchgeführt werden, wird über das Befehlswerkgesteuert, was für Berechnungen eigentlich durchgeführt werden sollen, wo die entsprechenden Zahlenim Speicher zu finden sind und so weiter. Rechenwerk und Befehlswerk sind intern im Prozessor überDaten- und Steuerbus verbunden.

Von-Neumann-Rechner

Struktur eines ComputersDer Prozessor als Gehirn des Computers ist extern über Daten-, Steuer- und Adreßbus mit dem Spei-cher und einer Ein- und Ausgabeeinheit verbunden. Die Ein- und Ausgabeeinheit kann wiederum mitexternen Peripheriegeräten verbunden sein.

Bekannte Prozessoren sind die Pentium-Chips von Intel. Der Speicher wird normalerweise als RAMabgekürzt, was für Random Access Memory steht (also sowohl les- als auch beschreibbarer Speicher).Ein- und Ausgabeeinheiten sind die Tastur, Monitor, Maus, aber auch beispielsweise die Festplatte.

Page 26: Allgemeine Grundlagen Der Programmierung

Rechnerarchitektur

21

Aufgaben

Übung macht den Meister1. Erstellen Sie aus den digitalen Grundschaltern einen Baustein mit vier Eingängen A, B, C und D

und einem Ausgang Y. Der Ausgang Y soll dann gesetzt sein, wenn mindestens A oder B gesetztist und zusätzlich mindestens C oder D.

2. Erstellen Sie aus den digitalen Grundschaltern einen Baustein mit drei Eingängen A, B und C undeinem Ausgang Y. Der Ausgang Y soll dann gesetzt sein, wenn A nicht gesetzt ist oder wenn Bgesetzt und gleichzeitig C nicht gesetzt ist.

3. Erstellen Sie aus den digitalen Grundschaltern eine EXKLUSIVE-ODER-Schaltung.

4. Erstellen Sie aus den digitalen Grundschaltern eine Schaltung mit zwei Eingängen A und B undeinem Ausgang Y. Der Ausgang Y soll nur dann gesetzt sein, wenn A und B nicht gesetzt sind oderwenn sowohl A als auch B gesetzt sind.

5. Für Experten: Erstellen Sie aus digitalen Grundschaltern, Halb- und Volladdierern eine Schaltung,die eine Subtraktion zwischen zwei 3-bit Zahlen durchführen kann. Eine Subtraktion wird technischwie folgt realisiert: Von der zu subtrahierenden Zahl wird das Zweier-Komplement gebildet wird.Das Zweier-Komplement ist eine mit dem NICHT-Operator negierte Zahl (Einser-Komplement),der der Wert 1 hinzuaddiert wird. Dann wird das Zweier-Komplement zur ersten Zahl hinzuaddiert.Das Ergebnis ist die Differenz der beiden Zahlen. Überprüfen Sie die Funktionsweise, indem Siedie Differenz von 7 und 2 anhand Ihrer Schaltung nachvollziehen.

Tipp

Die Aufgabe hört sich schwieriger an als sie ist. Sie müssen lediglich das Zweier-Kom-plement wie beschrieben bilden. Wenn Sie das Zweier-Komplement erst haben, führenSie eine Addition durch. Dazu verwenden Sie wie im Kapitel beschrieben Halb- und Vol-laddierer. Der Trick ist, dass eine Subtraktion eben nichts anderes ist als eine Addition,wenn man nur erst das Zweier-Komplement gebildet hat.

Page 27: Allgemeine Grundlagen Der Programmierung

22

Kapitel 4. ProgrammaufbauAllgemeines

Viele Wege führen nach RomBisher kennen Sie lediglich funktionale und objektorientierte Programmiersprachen, die jeweils ande-re Programmieransätze darstellen. Für den Anwender eines Programms ist jedoch grundsätzlich nichterkennbar, ob die Anwendung in einer funktionalen oder objektorientierten Sprache entwickelt wur-de. Diese Unterscheidung bezieht sich lediglich auf den Programmieransatz, also die Art und Weise,wie der Programmierer vom Problem zur Lösung gelangt. Dabei führen beide Wege zum Ziel. Keinefunktionale und objektorientierte Programmiersprache stellt grundsätzlich ein Hindernis dar, wenn esum die Entwicklung von bestimmten Computer-Anwendungen geht. Sie können sowohl in der einenals auch anderen Programmiersprache die gleichen Anwendungen entwickeln. Der Unterschied istder, dass es in der einen Programmiersprache wesentlicher leichter und schneller gehen könnte (immerabhängig von Art und Umfang des Programms, das entwickelt werden soll).

Für den Anwender hingegen machen sich andere Dinge bemerkbar. Wenn das Programm beispiels-weise eine intensive Berechnung ausführt, sollte es diese Berechnung "im Hintergrund" ausführen,damit der Anwender gleichzeitig mit anderen Funktionen des Programms weiterarbeiten kann. Dazumuss das Programm beispielsweise in der Lage sein, während die Berechnung abläuft gleichzeitig aufneue Benutzereingaben zu reagieren.

Das Ausführen paralleler Aufgaben innerhalb einer Anwendung erfordert spezielle Programmiertech-niken. In den bisher umgesetzten Beispielen war zu einem bestimmten Zeitpunkt immer nur eineAnweisung aktiv. Das Programm war zu jedem Zeitpunkt mit der Ausführung eines ganz bestimm-ten Befehls beschäftigt. Das Ausführen paralleler Aufgaben bedeutet, dass ein Programm zu einemZeitpunkt mehrere Anweisungen ausführen kann. Damit ist es beispielsweise möglich, eine intensiveBerechnung durchzuführen und gleichzeitig auf Benutzereingaben zu reagieren.

Multithreading

Mehrere ProgrammfädenDas Ausführen paralleler Aufgaben innerhalb einer Anwendung wird durch Multithreading gelöst.Verwechseln Sie Multithreading nicht mit Multitasking: Während Multithreading die parallele Aus-führung von Aufgaben innerhalb eines Programms ist, ist Multitasking die parallele Ausführung vonProgrammen durch das Betriebssystem. Sie als Programmierer können Ihr Programm multithrea-ding-fähig gestalten, über Multitasking entscheidet jedoch allein das Betriebssystem.

Multithreading bedeutet wortwörtlich, dass Ihr Programm mehrere Threads ausführt. Unter Threadsversteht man im Deutschen Programmfäden. Während unsere Beispielprogramme bisher alle nur auseinem Programmfaden bestanden, werden im Multithreading durch den Programmierer mehrere Pro-grammfäden gestartet. Mit den jeweiligen Programmfäden werden Funktionen verknüpft - es handeltsich hierbei also um eine Art Funktionsaufruf. Das Besondere ist jedoch nun, dass durch den Aufrufder Funktion diese gestartet wird und gleichzeitig die Funktion, aus der der Aufruf erfolgt, weiter aus-geführt wird. Ab diesem Zeitpunkt laufen also zwei Funktionen gleichzeitig, die jeweils unterschied-liche Aufgaben bearbeiten können.

Mit Multithreading können Sie Ihr Programm leistungsfähiger gestalten, weil unabhängige Aufgabenparallel ausgeführt werden können. Stellen Sie sich folgendes Beispiel vor: In Ihrem Programm müs-sen zwei Aufgaben durchgeführt werden. Beide Aufgaben bestehen aus insgesamt zehn Schritten,die nacheinander ausgeführt werden müssen. Während die erste Aufgabe pro Schritt 0,6 Sekundenbenötigt, ist die zweite Aufgabe rechenintensiver und benötigt pro Schritt 1,0 Sekunden. FolgenderJavascript-Code veranschaulicht dieses Beispiel.

Page 28: Allgemeine Grundlagen Der Programmierung

Programmaufbau

23

<html> <head> <title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript"> var Aufgabe1, Aufgabe2; var Schritt1 = 0, Schritt2 = 0;

function aufgabe_1() { var text = "Aufgabe 1: " + ++Schritt1 + ". Schritt<br>"; document.getElementsByTagName("body")[0].innerHTML += text; if (Schritt1 > 9) { window.clearInterval(Aufgabe1); Aufgabe2 = window.setInterval("aufgabe_2()", 1000); } }

function aufgabe_2() { var text = "Aufgabe 2: " + ++Schritt2 + ". Schritt<br>"; document.getElementsByTagName("body")[0].innerHTML += text; if (Schritt2 > 9) { window.clearInterval(Aufgabe2); } }

Aufgabe1 = window.setInterval("aufgabe_1()", 600); </script> </head> <body> </body></html>

Der Javascript-Code simuliert die Ausführung der Aufgaben, indem automatisch nach einem fest vor-gegebenen Zeitinterval eine bestimme Funktion gestartet wird, die jeweils eine Variable inkremen-tiert und dann den Wert dieser Variablen auf den Bildschirm ausgibt. Die erste Funktion wird hierbeialle 0,6 Sekunden aufgerufen, die zweite Funktion - die die rechenintensivere Aufgabe simuliert -alle 1,0 Sekunden. Wenn der zehnte Schritt der ersten Aufgabe erreicht und die erste Aufgabe somitkomplett ist, wird die zweite Aufgabe gestartet. Das heißt, die Aufgaben werden hintereinander aus-geführt - genau wie die Anweisungen in all den bisher kennengelernten Javascript-Programmen, dieauch jeweils eine nach der anderen ausgeführt wurden.

Wenn Sie die Zeit stoppen, die zur Ausführung der beiden Aufgaben benötigt wird, erhalten Sie 16Sekunden (aufgrund der verwendeten Funktionen in Javascript benötigt das Programm zur Ausführunginsgesamt 17,6 Sekunden, was aber nicht von entscheidender Bedeutung ist).

Zur Optimierung des Programms wird es umgeschrieben. Die beiden unabhängigen Aufgaben werdennun in zwei Threads ausgeführt. Nachdem Javascript das Erzeugen und Ausführen echter Threadsnicht ermöglicht, werden die Threads simuliert. Das heißt, das Ergebnis des Programms ähnelt demeines Programms mit echtem Multithreading.

<html> <head> <title>Allgemeine Grundlagen der Programmierung</title> <script type="text/javascript"> var Aufgabe1, Aufgabe2; var Schritt1 = 0, Schritt2 = 0;

function aufgabe_1() {

Page 29: Allgemeine Grundlagen Der Programmierung

Programmaufbau

24

var text = "Aufgabe 1: " + ++Schritt1 + ". Schritt<br>"; document.getElementsByTagName("body")[0].innerHTML += text; if (Schritt1 > 9) { window.clearInterval(Aufgabe1); } }

function aufgabe_2() { var text = "Aufgabe 2: " + ++Schritt2 + ". Schritt<br>"; document.getElementsByTagName("body")[0].innerHTML += text; if (Schritt2 > 9) { window.clearInterval(Aufgabe2); } }

Aufgabe1 = window.setInterval("aufgabe_1()", 600); Aufgabe2 = window.setInterval("aufgabe_2()", 1000); </script> </head> <body> </body></html>

Der Javascript-Code unterscheidet sich kaum vom vorherigen. Der Aufruf vonwindow.setInterval, um die Funktion aufgabe_2 als Thread zu starten, erfolgt nun nichtmehr innerhalb von aufgabe_1, sondern außerhalb. Der restliche Code ist identisch.

Das Programm löst nun die Aufgaben parallel in zwei Threads. Stoppen Sie die Zeit, die das Programmzum Durchlaufen aller zehn Schritte der zwei Aufgaben benötigt, und Sie sehen, dass nach 10 Sekun-den (genau 11 Sekunden) die Aufgaben beide komplett ausgeführt wurden. Das Erkennen parallelerAufgaben und das Entwickeln von Threads kann also die Ausführungsdauer extrem verkürzen - indiesem Fall um knapp 40 Prozent.

Kurz zur Erklärung der Javascript-Beispiele: Durch den Aufruf von window.setInterval wer-den die Funktionen, die als erster Parameter angegeben sind, wiederholt neu gestartet. In welchenZeitabständen die jeweiligen Funktionsaufrufe stattfinden legt der zweite Parameter fest, der eine Zeitin Millisekunden angibt. Das heißt also, die entsprechenden Funktionen werden einfach automatischimmer wieder von Zeit zu Zeit aufgerufen und ausgeführt.

Der Code in den Funktionsrümpfen bedeutet: Über den Zugriff auf die Eigenschaft innerHTML desObjekts mit dem HTML-Tag <body> wird dem Dokumentinhalt - also der Webseite selber - Texthinzugefügt. Dies geschieht unter Verwendung des kombinierten Zuweisungs-Operators +=. DieserOperator funktioniert so, dass der Code a += b äquivalent ist zum Code a = a + b. Der Text, derhinzugefügt wird, besteht aus der Ausgabe, welche Aufgabe gerade ausgeführt wird, dem Wert einerVariablen und einem Zeilenumbruch. Der Wert der Variablen wird über den Operator ++ vor seinerAusgabe jeweils um 1 erhöht. Das heißt, der Code ++a ist äquivalent zum Code a = a + 1.

Die Ausgabe von Text in das Dokument erfolgt jedoch nur, solange der Wert der Variablen kleinerals 10 ist. Ist dies nicht der Fall, weil die Variable bereits zehnmal um den Wert 1 erhöht wurde,wird die Funktion window.clearInterval aufgerufen. Diese Funktion bekommt jeweils dieVariable übergeben, die den Rückgabewert der Funktion window.setInterval entgegennahm.Der Wert der Variable ist hierbei unerheblich. Wichtig ist, dass es auf diese Weise möglich ist, eineentsprechende Funktion zu identifizieren. Über window.clearInterval kann dann mit Hilfe derVariablen die automatisch in regelmäßigen Abständen aufgerufene Funktion gestoppt werden und dasIntervall unterbrochen werden. Wenn also der Wert 10 in der Variablen erreicht ist, verhindert dieFunktion, auch weiterhin in Zukunft aufgerufen zu werden, indem sie die entsprechende Variable derFunktion window.clearInterval übergibt.

Page 30: Allgemeine Grundlagen Der Programmierung

Programmaufbau

25

Echtes Multithreading liegt dann vor, wenn eine Funktion als Thread aufgerufen wird und der Threaddann endet, wenn auch die Funktion beendet ist. Im Gegensatz hierzu muss in Javascript die entspre-chende Funktion immer wieder regelmäßig neu gestartet werden, um jedesmal neu Anweisungen aus-zuführen, die ansonsten in einem Multithreading-Programm alle gemeinsam in die Funktion gepacktwerden würden. Mit echtem Multithreading würde also beispielsweise eine while-Schleife in derFunktion von 0 bis 10 hochzählen und in jedem Schleifendurchgang eine Meldung auf den Bildschirmausgeben.

Polling

Wiederholtes ÜberprüfenEin gutes Programm soll, während es eine rechenintensive Operation ausführt, auch noch auf Benut-zereingaben reagieren. Beispielsweise sollte das Programm eine Schaltfläche Abbrechen zur Verfü-gung stellen, über die der Anwender jederzeit die rechenintensive Operation beenden kann. Auchin diesem Fall muss das Programm also zwei Aufgaben gleichzeitig ausführen: Berechnen und aufBenutzereingaben überprüfen. Andernfalls würde zuerst die Berechnung zu Ende geführt werden unddanach auf die Benutzereingabe überprüft werden. In diesem Fall wäre die Abbrechen-Schaltflächesinnlos, nachdem die Überprüfung erst nach der kompletten Berechnung stattfindet.

Als Programmierer könnte man nun auf folgenden Trick zurückgreifen. Während die langwierigeRechenoperation ausgeführt wird, könnte ja zwischendurch immer mal wieder überprüft werden, obder Anwender nun auf Abbrechen geklickt hat. Wenn beispielsweise die Rechenoperation aus einerSchleife besteht, die 10.000mal ausgeführt wird, könnte mit einer if-Anweisung innerhalb dieserSchleife ebenfalls ständig auf Benutzereingaben überprüft werden.

Dieses Modell ist als Polling bekannt - und so ungefähr das Schlimmste, was man als Programmie-rer machen kann. Polling bedeutet, dass man ständig innerhalb seines Programms überprüft, ob einbestimmtes Ereignis bereits eingetreten ist. Das Problem hierbei: Entweder führt man die Überprüfungin zu großen Zeitabständen aus, so dass das Programm erst verzögert auf Ereignisse reagiert, oder aberman fährt die Überprüfung in so kurzen Zeitabständen aus, dass man Rechenressourcen und Prozes-sorzeit verschwendet. Polling ist in jedem Fall Ressourcen-Verschwendung, weil man wiederholt aufEreignisse überprüft, die eventuell erst zu einem späten Zeitpunkt eintreten oder sogar gar nicht - derAnwender klickt beispielsweise nicht auf die Abbrechen-Schaltfläche, sondern wartet die Berechnungbis zum Ende ab.

Multiplexing

Hallo, ich hab da mal ein ErgebnisMultiplexing ist kein Konkurrenzmodell zu Multithreading. Während beim Multithreading Aufgabenparallel ausgeführt werden (und somit die einzelnen Threads im Vordergrund stehen), wird beim Mul-tiplexing die Anwendung zentral um einen Kern herum aufgebaut. Dieser Kern - normalerweise eineganz bestimmte Funktion des Betriebssystems - überwacht verschiedene Ein- und Ausgabegeräte. Trittein bestimmtes Ereignis ein, auf das die Anwendung wartet - also beispielsweise auf eine Eingabeüber die Tastatur - dann gibt der Kern eine entsprechende Meldung an die Anwendung weiter, dienun das Ereignis entsprechend behandelt. Ist dies erledigt, kehrt die Programmausführung zum Kernzurück, wo auf das nächste Ereignis gewartet wird oder bereits ein neues Ereignis vorliegt.

Multiplexing kann man als Gegenteil von Polling bezeichnen: Während beim Polling das Programmständig nachprüfen muss, ob ein Ereignis eingetreten ist, wird es beim Multiplexing automatisch infor-miert. Im Gegensatz zum Multithreading kann beim Multiplexing mit einer Funktion auf mehrereEreignisse gewartetet werden, anstatt in mehreren Threads jeweils auf ein Ereignis zu warten. Multi-plexing hat also den Vorteil, dass man auf mehrere Ereignisse gleichzeitig warten kann, ohne Threadsverwenden zu müssen. Das ist insofern interessant, als dass der Einsatz von Threads in der Praxisder Software-Entwicklung meist recht kompliziert ist, so dass Multiplexing vorgezogen werden soll-

Page 31: Allgemeine Grundlagen Der Programmierung

Programmaufbau

26

te. Da Multiplexing keinen Wechsel zwischen Threads benötigt, ist diese Technik außerdem ressour-cen-schonender und schneller als Multithreading. Multiplexing stellt jedoch keine Lösung dar, wennes um rechenintensive Aufgaben geht, die parallel ausgeführt werden müssen. In diesem Fall würdedie rechenintensive Behandlung eines Ereignisses bei Multiplexing verhindern, dass die Anwendungauf neue Ereignisse reagieren kann.

Durch Kombination von Multiplexing und Multithreading können Anwendungen erstellt werden, dieinformiert werden, wenn ein bestimmtes Ereignis eintritt, und die zur Behandlung von Ereignissenrechenintensive Operationen in Threads ausführen können.

Asynchrone Ein- und Ausgabe

Heute bestellt, morgen geliefertAls Konkurrenzmodell zu Multiplexing bietet sich die asynchrone Ein- und Ausgabe an. Diese Tech-nik ist so neu, dass sie kaum standardisiert ist und noch weniger in der Praxis der Software-Entwick-lung angewandt werden kann.

Asynchrone Ein- und Ausgabe liegt dann vor, wenn Ihr Programm beispielsweise einen Wert vonder Tastatur einlesen will (also eine Taste, die der Anwender gedrückt hat), beim entsprechendenLesevorgang im Programm jedoch angezeigt wird, dass der Anwender noch gar keine Taste gedrückthat. Daraufhin bearbeitet Ihr Programm einfach eine andere Aufgabe. Wenn der Anwender dann dieTaste drückt, wird das Programm sofort informiert, und eine entsprechende Ereignisbehandlung kannausgeführt werden.

Der Unterschied zu Multiplexing ist, dass das Programm nicht um einen Kern herum aufgebaut seinmuss und auf Meldungen aus dem Kern warten muss. Stattdessen kann das Programm machen, wases will - also auch jederzeit rechenintensive Operationen ausführen - und wenn dann ein entsprechen-des Ereignis eintritt, werden die laufenden Anweisungen unterbrochen und eine Ereignisbehandlungausgeführt. Asynchrone Ein- und Ausgabe vereint die Vorteile von Multiplexing und Multithreading.Threads sind lediglich dann noch interessant, wenn mehrere rechenintensive Aufgaben ausgeführtwerden sollen und die Ausführung durch Threads parallelisiert werden soll.

Das Modell ist asynchron, weil beim Abfragen eines Ereignisses dieses noch nicht eingetreten zusein braucht, bei Eintreten die entsprechende Information aber später automatisch nachgereicht wird.Eine Abwandlung vom rein asynchronen Ein- und Ausgabemodell stellt die signal-gesteuerte Ein-und Ausgabe dar, die nicht ganz so effizient arbeitet (jedoch auch heute schon in der Praxis der Soft-ware-Entwicklung angewandt werden kann).

Aufgaben

Übung macht den Meister1. Für Experten: Entwickeln Sie eine Javascript-Lösung für Aufgabe 4 aus Kapitel 2 (Umrechnung

einer Dezimalzahl in eine Hexadezimalzahl) unter Verwendung eines Threads.

Tipp

Anstatt die Division- und Modulo-Operation jeweils in einem Schleifendurchgang neudurchzuführen, müssen diese Schritte durch den wiederholten Aufruf einer Funktion aus-geführt werden.