Letzte Änderung:
20.03.2012
Bertolt Brecht
20.03.2012
Spruch des Tages
Wer die Wahrheit nicht weiß, der ist bloß ein Dummkopf. Aber wer sie weiß und sie eine Lüge nennt, der ist ein Verbrecher.Bertolt Brecht
Wozu benötigen wir Software?
Zur Bearbeitung einer Aufgabenstellung benötigt der Computer Anweisungen (=Algorithmen). Diese Algorithmen zur Lösung der gestellten Aufgaben ergeben ein Programm. Geschrieben werden sie in Programmiersprachen. Die so erzeugten Algorithmen werden dann von speziellen Programmen in die Maschinensprache übersetzt (eine für den Computer verständliche Sprache). Zusammenfassend kann festgehalten werden, dass eine Programmiersprache neben vielen anderen Aufgaben im Wesentlichen die Aufgabe eines Translators erfüllt. Eine Software umfasst nicht nur das lauffähige Programm. Dazu gehören je nach Zielstellung Datenbanken, Treiber, Hilfedateien, Tools, Anleitungen und vieles mehr. Das EVA- Prinzip Jede Software arbeitet nach dem EVA – Prinzip.
Eine Software kann Daten erst verarbeiten, wenn diese zuvor erfasst wurden. Das gilt für jedes denkbare Programm. Und Programme gibt es nicht nur für den Computer. Wenn Sie z. B. in ein Parkhaus fahren, fordern Sie im Regelfall durch einen Tastendruck die Freigabe, also das Öffnen der Schranke, an. Hier gilt das gleiche Prinzip:
Die Eingabe steht an erster Stelle vor der Verarbeitung. Und die darauf folgende Ausgabe muss sich nicht immer durch eine Bildschirmanzeige manifestieren. Das Öffnen der Schranke (die Reaktion) entspricht hier der Ausgabe. In der Computertechnik gibt es neben den zu erwartenden Ein- und Ausgabegeräten – wie Tastatur, Maus und Monitor – vielfältige Möglichkeiten der Ein- und Ausgabe. Denken Sie dabei beispielsweise an optische Sensoren, Temperaturfühler und mechanische Verarbeitung, wie bei CNC-Maschinen.
Warum Programmieren?
Bei der Vielzahl der bereits existierenden Programme stellt sich die Frage, inwieweit es überhaupt noch Sinn macht, das Programmieren zu erlernen. Die Antwort auf diese Frage ist: Obwohl bereits sehr viele Programme existieren, ist der Bedarf an neuer Software immer noch sehr groß. Dies wird zum einen verursacht durch neue Anwendungsgebiete, technische Neuerungen und Änderungen von gesetzlichen Vorschriften, zum anderen durch Software, die veraltet ist (z.B. DOS-Programme) oder gepflegt (Updates) werden muss. Dieser Markt hat in den vergangenen Jahren, insbesondere zur Jahrtausendwende, an Bedeutung gewonnen.
Grundbegriffe des Programmierens
Wenn ein Mensch in ein neues Wissensgebiet eindringt, dann muss er sich darüber im Klaren sein, dass er in diesem Wissensgebiet mit Wörtern konfrontiert wird, die diesem Wissensgebiet eigen sind. An dieser Stelle werden nun einige dieser Grundbegriffe erläutert. Im weiteren Verlauf dieses Kurses werden Sie noch eine Vielzahl weiterer Begriffe kennenlernen; eine Erklärung aller Begriffe ist an dieser Stelle nicht zweckmäßig.
Eine Programmiersprache ist eine Sprache, mit deren Hilfe der Programmierer ausdrücken kann (oder: Befehle erteilen kann) welche Arbeiten von einem Computersystem ausgeführt werden sollen.
Ein Programm ist eine Aneinanderreihung von Befehlen, über die der Programmierer, mittels einer Programmiersprache, dem Computersystem mitteilt, welche Arbeit von dem System verrichtet werden soll.
Der Sourcecode ist das Programm, das der Programmierer in einer Programmiersprache codiert (editiert).
Der Begriff Syntax beschreibt in der Programmierung (genau wie in der natürlichen Sprache), die Form sowie die Beziehung der einzelnen Elemente und ihre Abfolge. Im Fall der Programmierung handelt es sich dabei nicht um Sätze, sondern um die richtige Form und Folge von Befehlen und Zeichen.
Klassifizierung von Software
Standardsoftware wird für ein breites Einsatzgebiet entwickelt. Es handelt sich hierbei um Applikationen, die für eine Vielzahl von Anwendern entwickelt werden. Stellvertretend für viele andere Anwendungen sind hier insbesondere die folgenden Gebiete zu benennen:
Textverarbeitung Tabellenkalkulationen Datenbanken Webanwendungen Spiele
Individualsoftware sind Applikationen, die für ganz spezielle Aufgaben entwickelt werden. Fast immer handelt es sich hier um Entwicklungen, die nur für einzelne Anwender oder spezielle Anwendungsgebiete konzipiert wurden. Häufig sind diese Applikationen im technischen Bereich anzutreffen (z. B. Ansteuerung von Maschinen oder Messwerterfassung).
Klassifizierung nach Sprachtypen und Familien
Im Laufe der Zeit sind einige tausend Programmiersprachen entstanden. Die nachfolgende Gruppierung nach Generationen stellt eine historische Entwicklung dar, sie ist aber nicht so zu bewerten, dass Programmiersprachen der ersten Generationen nicht mehr up-to-date sind. Vielmehr sind die Anforderungen an Software, insbesondere an ihre Komplexität über die Jahre gestiegen und daraus entwickelten sich die jeweiligen Generationen. Je nach Komplexität der Problemstellung und auch nach wirtschaftlichen und sachlichen Überlegungen werden heute bei der Wahl einer Programmiersprache alle vorhandenen Generationen in Erwägung gezogen und bei der Auswahl berücksichtigt. Es kommen also auch bei aktuellen Problemlösungen nicht ausschließlich Sprachen der neuesten Generation zum Einsatz. Im Allgemeinen werden die Programmiersprachen in fünf Generationen unterteilt. Eine Erläuterung zu den einzelnen Generationen finden Sie in der Folge.
Erste Generation: Maschinensprachen
Maschinensprachen werden heute so gut wie nicht mehr verwendet, da ein Maschinensprachen-Programm für den Menschen nur sehr schwer lesbar ist. Ein Anwendungsgebiet ist jedoch auch heute noch die direkte Programmierung von Mikroprozessoren. Hierbei werden einzelne Anweisungen, die der Mikroprozessor ausführen soll, in Maschinensprache verfasst. Diese Anweisungen werden speziell für einzelne Maschinen geschrieben und werden daher als plattformabhängig bezeichnet. Fast jeder Mikroprozessor-Operationscode wird auch heute noch in Maschinensprache verfasst. Er dient dazu, die Signalleitungen innerhalb des Prozessors zu steuern.
Die Darstellung erfolgt binär.
Beispiel: 000000000011100011111001010101010110010000111
Zweite Generation: Assembler Sprachen
Assemblersprachen werden im Wesentlichen zur Programmierung der Hardware (z. B. Ansteuerung von Maschinen) und für zeitkritische Anwendungen genutzt. Der Assembler ist dabei ein Werkzeug, welches den Sourcecode, den der Programmierer eingegeben hat, in Maschinensprache übersetzt. Da diese Art der Programmierung sehr stark von der jeweiligen Maschine abhängig ist, für die diese Programme gedacht sind, ist auch hier eine Plattformabhängigkeit gegeben.
Beispiel:
SUB 7, 2
ADD 6, 7
MOV
Dritte Generation: Problemorientierte Sprachen
Im Zuge der Softwareentwicklung wurden die Applikationen immer komplexer und somit wurde es für die Entwickler von Software immer schwieriger, die Programme zeitnah fertig zu stellen. Daher entstand die Idee, eine neue Generation von Programmiersprachen zu entwickeln. Diese werden als problemorientierte oder auch höhere Programmiersprachen bezeichnet. In diesen Programmiersprachen werden Befehle, die in Assembler noch aus mehreren oder vielen Zeilen bestanden, in eine für den Menschen gewohnte Sprache zusammengefasst. So wurde eine bessere Lesbarkeit und Übersichtlichkeit erreicht. In der Folge konnten nun auch komplexere Anwendungen zeitnah erstellt werden. Zu diesen Vorteilen gesellte sich noch, dass diese Programmiersprachen leichter und somit auch von einer größeren Masse erlernbar waren. Vorreiter dieser Generation waren die Programmiersprachen „Fortran“ (1957), „Algol“ (1963) und „Cobol“ (1959). Später entwickelten sich dann weitere Sprachen. Zu den wohl bekanntesten gehören „C“ (1972) und „Pascal“ (1972). Die Programmiersprache „Basic“ wurde zwar bereits 1963 entwickelt, gewann jedoch erst Mitte der 70er Jahre an allgemeiner Bekanntheit.
Beispiel einer Anweisung (eines Statements): Mehrwertsteuer = Umsatz / 119 * 19
Das Konzept der prozeduralen Programmiersprachen: Die vorgenannten Programmiersprachen werden auch als prozedurale Programmiersprachen bezeichnet. Dahinter steckt das Konzept, komplexe Probleme in Teilprobleme, sogenannte Prozeduren, zu unterteilen, wobei das kleinste und somit unteilbare Teilproblem eine einzelne Anweisung darstellt. Dabei schreitet das Programm in seinem Ablauf von einer Anweisung zur Nächsten voran. Aus dieser Vorgehensweise leitet sich auch der Name „prozedural“ ab (lat. procedere = voranschreiten). In diesem Zusammenhang tauchen auch häufig die Begriffe der Funktionen und Methoden auf, die häufig synonym benutzt werden. Eine eindeutige Definition der Unterscheidung der Genannten lässt sich nur anhand der jeweils verwendeten Programmiersprache vornehmen. Das Ziel des Programmierers bei Anwendung des Konzepts der prozeduralen Programmiersprachen ist es, mittels der Unterteilung in Teilprobleme eine erhöhte Übersichtlichkeit und somit Sicherheit sowie eine Wiederverwendbarkeit zu schaffen. Auf diese Weise können einmal geschriebene und erprobte Prozeduren in weiteren Applikationen (Anwendungen, Programmen) wiederverwendet werden, ohne diese jedes Mal wieder neu zu entwickeln.
Das Konzept der objektorientierten Programmiersprachen:
Anfang der 80er Jahre entwickelte sich ein neues Konzept der Programmierung, die objektorientierte Programmierung (OOP). Ziel dieses Konzeptes war und ist es, die zu verarbeitenden Daten anhand ihrer Eigenschaften und der daraus möglichen Operationen zu klassifizieren. Hierbei werden Objekte aus der realen Welt nachgebildet. Dieses Thema ist allerdings nicht Bestandteil dieser Unterrichtseinheit und wird deshalb nicht tiefer behandelt
Vierte Generation: Deklarative Sprachen
Der Programmierer beschreibt das Ziel (was möchte ich haben), aber nicht die Algorithmen (wie soll dies geschehen). Durch diese Vorgehensweise sind Sprachen der vierten Generation nur für spezielle Aufgaben nutzbar, beispielsweise Datenbankabfragen. Sie werden oft in Verbindung mit den Sprachen der dritten Generation genutzt. Bekannte Vertreter sind die Sprachen SQL, LISP, ML und Prolog.
Beispiel SQL: SELECT Vorname, Name FROM Adressen WHERE PLZ = 86199;
Fünfte Generation: Künstliche Intelligenz (KI)
Die Sprachen der fünften Generation beschäftigen sich mit der Nachbildung intelligenten Verhaltens. Es werden mindestens vier Intelligenzarten unterschieden:
• visuelle Intelligenz
• sprachliche Intelligenz
• manipulative Intelligenz
• rationale Intelligenz
Insbesondere Entwicklungen der Robotik als Bestandteil der KI werden vermehrt durch die Öffentlichkeit zur Kenntnis genommen. Besonders augenfällig sind die regelmäßigen Berichte selbst fahrender Automobile.
Beispiel: Das folgende Beispiel ist in unserer natürlichen Sprache formuliert, um die Prinzipien der KI aufzuzeigen:
Folgende Fakten seien gegeben: • Petra ist die Mutter von Karin. • Petra ist die Mutter von Michael. • Karin ist die Mutter von Susanne.
Daraus kann folgende Regel abgeleitet werden:
• Wenn X die Mutter von Y ist und Y die Mutter von Z ist, dann ist X die Großmutter von Z.
Frage: • Wer ist die Großmutter von Susanne?
Schlussfolgerung aus den Informationen und Regeln: • Petra
Compiler, Interpreter und Debugger
Computerprogramme werden im Allgemeinen in einer Programmiersprache geschrieben, die dem Menschen verständlich ist. Der Sourcecode der gewählten Programmiersprache kann in der Regel in einem einfachen Editor eingegeben werden.
Diese Quellsprache wird allerdings vom Computer nicht verstanden. Deshalb bedient sich der Programmierer eines Werkzeugs zur Übersetzung bzw. Ausführung in einer „maschinenverständlichen“ Sprache.
Zur Übersetzung kann er im Wesentlichen, je nach Programmiersprache, zwei unterschiedliche Werkzeuge einsetzen und dabei insgesamt drei unterschiedliche Wege beschreiten. Die Werkzeuge werden als Compiler und Interpreter bezeichnet.
Weg 1: der Compiler
Der Compiler, auch Übersetzer genannt, ist in seinem Ursprung eine Software, die den Sourcecode des Programmierers nach verschiedenen Überprüfungen in eine für den Prozessor verständliche Maschinensprache übersetzt und speichert. Bei der Überprüfung des Sourcecodes, der sogenannten Analysephase, übernimmt der Compiler die Aufgabe der Syntaxüberprüfung (Rechtschreib- und Grammatikprüfung). Abschließend wird noch eine semantische Überprüfung vorgenommen. Dabei wird z. B. kontrolliert, inwieweit verwendete Namen auch zuvor korrekt definiert (deklariert) wurden. Eine Überprüfung der Programmlogik kann – zum Leidwesen des Programmierers – nicht stattfinden, da nur der Programmierer, aber nicht der Compiler die Aufgabenstellung kennt. Sollte wider Erwarten ein Fehler durch den Compiler diagnostiziert werden, erfolgt eine Fehlermeldung, die wie folgt aussehen könnte:
C:Programmetest.java:6: cannot find symbol
Nach der Überprüfung des Sourcecodes erfolgt die Übersetzung in die Maschinensprache, diese Phase wird als Synthesephase bezeichnet. In der Microsoft™-Welt erkennt man Kompilate, also von Compilern erzeugte Dateien, an den Dateiendungen „.exe(cute)“ bzw. „.com(pilate)“. Es handelt sich dabei stets um direkt ausführbare Programme.
Der Vorteil des Einsatzes eines Compilers in seiner Ursprungsform liegt darin, dass das Programm stets syntaktisch und semantisch fehlerfrei ist und nur ein einziges Mal übersetzt werden muss. Dies hat zur Folge, dass diese Kompilate im Gegensatz zu den folgenden Vorgehensweisen wesentlich schneller ausgeführt werden. Der Nachteil ist darin zu sehen, dass diese Kompilate stets plattformabhängig sind, d. h. sie können nur auf Plattformen (Hardware, Software) eingesetzt werden, für die sie auch kompiliert wurden. So kann ein Kompilat für Windows™ nicht ohne Weiteres auf einer Maschine, die beispielsweise unter Linux oder auch einem anderen Betriebssystem läuft, ausgeführt werden. Bekannte Sprachen, die dieses Verfahren nutzen, sind Fortran, Cobol, C, C++, Pascal, Delphi.
Weg 2: der Interpreter
Der Interpreter ist eine Software, der in seiner Ursprungsform den Sourcecode eines Programms zeilenweise einliest, auf syntaktische Fehler überprüft und ausführt. Die wohl bekannteste Interpreter-Sprache ist HTML. Nennenswerte sind auch Perl, PHP und JavaScript. Bekannte Interpreter sind der Internet Explorer™ oder Mozilla Firefox.
Der Vorteil von Interpretern liegt in der Möglichkeit, den Quellcode aufgrund des im Gegensatz zu Kompilaten deutlich geringeren Speichervolumens zügig per Datenfernübertragung auf den verarbeitenden Rechner zu übertragen und ihn dort auszuführen. Der Quellcode ist dabei plattformunabhängig, hingegen ist der Interpreter, der den Quellcode ausführt, plattformabhängig.
Der Nachteil des Interpreters liegt darin, dass der Sourcecode immer wieder zur Laufzeit (Programmausführung) überprüft und interpretiert werden muss und dies natürlich im Vergleich zu Kompilaten deutlich mehr Zeit in Anspruch nimmt.
Weg 3: der Compiler in Kombination mit dem Interpreter
Neben der ursprünglichen Form des Compilers existiert noch eine weitere Form des Kompilierens. Dabei wird, genauso wie beim ursprünglichen Compiler, eine syntaktische und semantische Überprüfung durchgeführt, jedoch ist das Resultat nicht Maschinensprache, sondern ein Zwischencode, der plattformunabhängige Byte-Code. Dieser Byte-Code ist, durch die vorhergehende Überprüfung, frei von syntaktischen Fehlern. Er ist im Verhältnis zu ausführbaren Kompilaten recht klein und somit, ähnlich wie der Sourcecode bei der Interpreter-Variante, recht schnell per Datenfernübertragung auf ausführende Rechner zu übertragen oder auf Geräten mit geringer Speicherkapazität, wie Handys, ohne Kapazitätsprobleme unterzubringen. Der Byte-Code benötigt jedoch zur Ausführung des Byte-Codes einen plattformabhängigen Interpreter, der den Byte-Code interpretiert und ausführt. Dadurch, dass bereits eine Überprüfung auf Korrektheit durchgeführt wurde, findet diese zur Laufzeit nicht mehr statt. Das Resultat ist eine Geschwindigkeitssteigerung gegenüber der „reinen“ Interpreterversion, die Geschwindigkeit eines „reinen“ Kompilats wird jedoch nicht erreicht. Bekannte Sprachen, die diesen Weg des plattformunabhängigen Zwischencodes beschreiten, sind die Programmiersprachen Java und C#.
Bei der Programmiersprache Java trägt der plattformabhängige Interpreter den Namen Java Virtual Maschine (JVM).
Der Debugger
Ein Debugger ist ein Unterstützungstool zum Diagnostizieren, Auffinden und Beheben von logischen Fehlern in Programmen. Mit Hilfe eines Debuggers kann z. B. ein Programm step-by-step durchlaufen und die Inhalte von Variablen angezeigt werden, dabei können sogenannte Bugs (Fehler) ermittelt werden.
Interne Abarbeitung von Programmen
Bei der internen Abarbeitung von Programmen ist das Prozedere immer das gleiche. Wenn Sie ein Programm starten, wird dieses Programm in den Arbeitsspeicher geladen. Dabei wird eine Kopie (Instanz) des Programms im Arbeitsspeicher erstellt. In jedem Programm befindet sich eine Stelle an der der Computer mit der Abarbeitung des Codes beginnt. Dies ist bei allen Programmen gleich, denn der Computer muss wissen wo er mit seiner Arbeit beginnen soll. Diese Stelle wird im Allgemeinen als Hauptprogramm bezeichnet. In Java, der Programmiersprache, mit der Sie in diesem Kurs arbeiten werden, hat diese Stelle den Namen main. Der Computer „sucht“ nun, nachdem das Programm in den Arbeitsspeicher geladen wurde, diese Stelle und beginnt mit seiner Arbeit. Je nach Programmiersprachengeneration – hierzu später mehr – wird das Programm nun, beginnend am Startpunkt, zeilenweise abgearbeitet. Bei dieser Abarbeitung werden die Befehle, die der Programmierer editiert hat, vom Computer umgesetzt. Dabei kann es sich um die unterschiedlichsten Befehle handeln, wie z.B. Berechnungen, Bildschirmausgaben oder Eingabeaufforderungen. Neben diesen einfachen Anweisungen können Konstrukte für Verzweigungen oder Wiederholungen verwendet werden. Das Ausführen bzw. Abarbeiten der Befehle wird so lange fortgeführt, bis das Ende des Programms erreicht ist. Danach wird der Arbeitsspeicher für andere Programme oder Daten zur Verfügung gestellt.