Technische Probleme lösen mit C/C++ - Von der Analyse bis zur Dokumentation

Norbert Heiderich, Wolfgang Meyer

Technische Probleme lösen mit C/C++

Von der Analyse bis zur Dokumentation

2016

359 Seiten

Format: ePUB

E-Book: €  26,99

E-Book kaufen

E-Book kaufen

ISBN: 9783446451698

 

2 Erste Gehversuche mit C/C++

Dieses Kapitel beschäftigt sich mit einigen grundlegenden Aspekten der Programmiersprache C/C++. Neben der Frage, warum es sinnvoll ist, gerade mit C/C++ zu arbeiten, werden Funktionsweisen der Komponenten der Entwicklungsumgebung betrachtet und erläutert. In den folgenden Kapiteln werden zunächst Beispiele in klassischem C als Konsolenanwendungen realisiert, bevor später objektorientiert mit C++ weitergearbeitet wird. Dann sind die Beispiele auch mit grafischen Oberflächen ausgestattet.

2.1  Warum gerade C/C++?

Wer C/C++ erlernen will, hat sich für eine Programmiersprache entschieden, die auf fast allen Rechnertypen und unter fast allen Betriebssystemen verfügbar ist. Es steht Ihnen, anders als bei vielen anderen Programmiersprachen, auf den verschiedensten Entwicklungsplattformen eine genormte Standard-Bibliothek zur Verfügung. Damit gelingt eine einheitliche Implementierung der mit dieser Programmiersprache erstellten Programme mit sehr hoher Geschwindigkeit.

C wird auch als Highlevel-Assembler bezeichnet, also als Programmiersprache, die sehr nah an der Maschinensprache ist. Dies beruht auf der Tatsache, dass der Kern (bzw. Kernel) aller gängigen Betriebssysteme in C geschrieben wurde. Damit eignet sich C/C++ auch in besonderem Maße für die Systemprogrammierung, also für Programme, die für den Betrieb von Rechenanlagen erforderlich sind.

Dank der relativ einfachen Struktur und dem geringen Umfang der eigentlichen Sprache, d.h. der verfügbaren Schlüsselworte der Programmiersprache, war es möglich, C-Compiler, also spezielle Programme zur Übersetzung des vom Programmierer erstellten Codes in eine maschinenverständliche Sprache, für alle Arten von Prozessorplattformen zu entwickeln, so dass die Programmiersprache C/C++ heute für die gesamte Leistungspalette vom Mikrocontroller bis zu High-End-Rechnern verfügbar ist. Für den Entwickler von Software bedeutet dies: Egal für welche Prozessorplattform programmiert wird, einen C-Compiler wird man für das relevante Zielsystem bekommen. Man braucht sich nicht um eine Programmierung zu kümmern, die spezifisch für den jeweiligen Zielprozessor ist. In den meisten Fällen wird es möglich sein, die auf einer Plattform entwickelte Anwendung auf einer anderen Plattform auszuführen. Der erforderliche Anpassungsaufwand ist in aller Regel sehr überschaubar.

Das bedeutet nicht, dass man fertige Programme von einer Plattform auf eine andere übertragen kann (etwa von einem Windows-PC auf einen Linux-PC) und diese dann auf der neuen Plattform (also unter Linux) sofort wieder funktionieren. Vielmehr ist nur die problemlose Übertragung der Quelltexte auf ein neues System gemeint, auf dem diese dann mit dem entsprechenden Compiler und Linker (ein Linker oder Binder ist ein Programm, das einzelne Programmmodule zu einem ausführbaren Programm verbindet) in ein funktionierendes Programm umzuwandeln sind!

Die Tatsache, dass Programme, die in C/C++ geschrieben werden, sehr klein sind (nur in Assembler ‒ also Maschinensprache ‒ geschriebene Programme sind noch kleiner), macht C/C++ zu einer wichtigen Programmiersprache im Bereich Embedded Systems (also Systemen, die stark einschränkenden Randbedingungen unterliegen, wie geringe Kosten, Platz-, Energie- und Speicherverbrauch) und der Mikrocontroller-Programmierung, wo Speicherplatz ebenfalls sehr kostbar ist.

Ein C/C++-Programm wird mithilfe eines Compilers (dem Übersetzer des Quelltextes) aus einer oder mehreren einfachen Textdateien zu Objektcodedateien übersetzt. Diese Objektcodedateien werden anschließend von einem Linker (bzw. Linkage-Editor = Binder, Werkzeug für das Zusammenfügen übersetzter Programmteile) mit den erforderlichen Systembibliotheken zu einer ausführbaren Datei (der Executable ‒ oder kurz EXE-Datei) zusammengebunden.

Jedes ausführbare C/C++-Programm besitzt eine Hauptfunktion. In C wird diese Hauptfunktion als bezeichnet.

Damit das Betriebssystem erkennen kann, wo der Einstiegspunkt für den Ablauf eines C/C++-Programms zu finden ist, muss diese Namenskonvention unbedingt eingehalten werden. Auch wenn andere Entwicklungsumgebungen als das Visual Studio von Microsoft oder andere Compiler eingesetzt werden, ändert sich an diesem Einstiegspunkt nichts. Variieren kann allenfalls die Parametrisierung (also die Art, Anzahl oder der Datentyp der Übergabeparameter) dieser Hauptfunktion. Dieser Aspekt wird später in Kapitel 4.8, in dem es um Funktionen gehen wird, noch ausführlich erläutert.

Darüber hinaus ist es natürlich auch möglich, eigene Programme und/oder Funktionen in eigenen Bibliotheken zusammenzufassen, um diese später erneut benutzen zu können. Diese Bibliotheken können bei einem späteren Bindevorgang durch den Linker wieder verwendet werden, damit diese dann zu einem neuen Programm hinzugebunden werden.

2.2  Compiler und Interpreter

Die höheren Programmiersprachen (dazu zählen u.a. FORTRAN, ALGOL und C/C++) sind entwickelt worden, damit die Beschreibung eines Lösungsverfahrens, der Algorithmus, in einer für Menschen einfacher lesbaren Form erfolgen kann und nicht in Maschinencode vorliegen muss. Der Programmierer als der Anwender solcher Programmiersprachen soll sich also auf die Lösung seiner konkreten Aufgabenstellung konzentrieren können, ohne sich zu sehr mit den Interna des Rechners beschäftigen zu müssen. Ein weiterer, nicht zu vernachlässigender Vorteil ist, dass Programmiersprachen normalerweise unabhängig von der Maschine sind, auf der die Programme ausgeführt werden.

Die Tatsache, dass es zwei verschiedene Verfahren zur Erzeugung von Programmen gibt, deutet das Problem an, das sich hinter der Verwendung einer Programmiersprache verbirgt: die Programme können nicht mehr direkt und unmittelbar vom Computer gelesen und zur Ausführung gebracht werden, sondern sie müssen erst in eine vom Computer interpretierbare passende Darstellungsform gebracht werden.

Eine Möglichkeit Quellprogramme (also die vom Programmierer erstellten und für den Programmierer lesbaren Textdateien mit den Programmen) zu übersetzen, sind Interpreter. Bei ihnen wird das Programm Zeile für Zeile gelesen und bewertet, wobei Schreibfehler oder Verstöße gegen die Regeln der Programmiersprache, Syntaxfehler, festgestellt werden. Danach führt der Interpreter die mit den Anweisungen verbundenen Befehle und Aktionen aus. Die Arbeitsweise solcher Interpreter kann wie in Bild 2.1 dargestellt werden.

 

Bild 2.1 Arbeitsweise eines Interpreters

Der große Vorteil interpretierter Programme besteht darin, dass es möglich ist, schnell einmal etwas auszuprobieren oder während des Programmablaufs einzugreifen und Werte von Variablen zu betrachten oder zu verändern. Für professionelle Projekte dagegen sind Interpreter eher ungeeignet. Zuerst einmal ist da das Problem der mangelnden Geschwindigkeit zu nennen. Denn egal, ob ein Programm zum ersten oder tausendsten Mal ausgeführt wird, alle zugehörigen Programmzeilen durchlaufen immer wieder den Zyklus: Lesen ‒ Bewerten ‒ Ausführen.

Außerdem ist nur ein geringer Schutz des Quellcodes vor Eingriffen von außen gegeben. Der Anwender hat jederzeit die Möglichkeit den Code zu manipulieren, ohne sich mit dem Programmierer abzusprechen. Es entstehen so in der Praxis ziemlich schnell alternative Programmversionen, die bei einem neuen Release zu großen Problemen führen.

Der andere Lösungsansatz, um ein ausführbares Programm zu erzeugen, führt über den Einsatz eines Compilers. Ein Compiler ist ein Programm, das einen Quellcode einliest und ihn zunächst auf syntaktische Fehler untersucht. Werden keine wirklichen Fehler festgestellt, so wird der Quellcode in eine maschinenlesbare Form übersetzt.

Nach dem abschließenden Schritt des Bindens (Linken) liegt das Programm in einer Form vor, die auf dem Rechner, auf dem es verarbeitet wurde, lauffähig (also ausführbar) ist (engl. executable, daher die Extension (Programmendung) EXE). Dieses Programm kann nun unabhängig von Quellcode und Compiler ausgeführt werden. Diese Arbeitsweise lässt sich wie in Bild 2.2 darstellen.

 

Bild 2.2 Arbeitsweise eines Compilers und Linkers

Der große Vorteil dieser Vorgehensweise liegt darin, dass die Programme ohne Preisgabe des Quellcodes lauffähig sind. So können z.B. auch im Quellcode verwendete Betriebsgeheimnisse von keinem Anwender mehr eingesehen werden. Vor allen Dingen aber laufen solche Programme sehr viel schneller ab als interpretierte Programme, da ja die Interpretation jedes Programmstatements (also jeder Programmzeile) entfällt. Die Überprüfung hat bereits bei der Kompilierung (also der Übersetzung in die Object-Datei) stattgefunden. Ein gewisser Nachteil besteht zweifellos darin, dass nun bei jeder Programmänderung der komplette Zyklus Editieren ‒ Übersetzen ‒ Starten durchlaufen werden muss, bevor man etwas in einem Programm ausprobieren kann. Das kostet in der Testphase natürlich etwas mehr Zeit als bei interpretativen Programmen. Denn auch beim Auftreten eines syntaktischen Fehlers muss man immer erst wieder das Programm in den Editor laden, den Fehler beheben und die Übersetzung (Kompilierung) von neuem starten.

Deutlich entschärft wird dieses Problem dadurch, dass die meisten Compiler heutzutage mit einer sogenannten integrierten Entwicklungsumgebung ausgestattet sind, in der der Editor und der Compiler eine...

 

© 2009-2024 ciando GmbH