PROGRAMMIEREN IN "C"

Unabhängigkeitserklärung der Software-Entwickler

04.01.1991

Ursprünglich speziell für die effiziente und systemnahe Programmierung unter Unix konzipiert, befindet sich C mittlerweile auf einem Siegeszug durch alle Anwendungsbereiche und Betriebssysteme. Für C-Spezialist Anton Illik* ist das nicht verwunderlich: Die Sprache vereinigt nicht nur das Beste aus allen Welten, sie hält auch die Tür zu diesen Welten offen.

Genealogie von C

Vom Mauerblümchen zum Superstar: C + + vorhabe der objektorientierten Programmierung zum Durchbruch und machte C endgültig zur Sprache der Zukunft.

Eine Sprache für alle Systeme?

C ist der Yuppie unter den Programmiersprachen - effizient, elegant, schnell, erfolgreich und skrupellos. Eine Sprache für Echte Programmierer.

An C scheiden sich die Geister. Kaum eine Sprache wird so sehr geliebt und so sehr gehaßt. Und was die einen hassen an ihr, ist gerade das, was die anderen lieben: ihre Knappheit und ihre Freizügigkeit. Mit C ist alles möglich, im Guten wie im Bösen. Lesbar für einen Zweiten ist es nicht immer.

Das wäre nicht weiter bemerkenswert, wäre diese Sprache nicht gleichzeitig auf dem besten Weg, zur dominierenden Universalsprache zu werden. Schon bald wird sie Assembler in den meisten Bereichen ersetzt haben. An den Universitäten hat sie längst Basic und Pascal den Rang abgelaufen, und mit den Studenten dringt sie bereits in die alten Fortran-Hochburgen ein. Selbst Cobol könnte mit der Zeit in Bedrängnis kommen: Fast jede Datenbank bietet heute mit als erstes eine Programmier-Schnittstelle zu C.

Die einstige Spezialsprache für ein exotisches Uni-Betriebssystem ist zur lingua franca der DV-Welt geworden. Mit ihr rückt erstmals eine " Verständigung" über alle Systemgrenzen in greifbare Nähe - eine Verständigung von der viele viel Profitieren könnten.

In dem Maß, in dem die Software austauschbar wird, werden die Systeme vergleichbar und da mit am Ende selbst austauschbar. Wer seine Programme in C geschrieben hat, kann sie Mit vertretbarem Aufwand auch auf einer anderen Plattform zum Laufen bringen. Dem Software-Anbieter bringt das einen neuen Markt, dem Anwender eröffnet es bessere Chancen, sein System auch wechseln zu kennen, wenn es denn einmal nötig sein sollte. Für beide bedeutet es zudem, daß sie keine neuen Spezialisten einstellen müßten für die neue Plattform.

C ist sicher nicht die eine Sprache für Oberhaupt alles, dazu ist sie viel zu sehr eine Programmierer-Sprache. Aber sie zu ignorieren könnte ein Fehler sein. Denn bei der Entscheidung, in welcher Sprache man seine Software schreiben beziehungsweise schreiben lassen soll, geht es weniger um Vorlieben als um eine Menge Geld. gs

In der Industrie wird die Sprache C hauptsächlich in der Systemprogrammierung und der systemnahen Programmierung eingesetzt. Beim Bau von Assemblern, Compilern, Betriebssystemen, Programmierumgebungen, Testsystemen und vielem anderen mehr hat sich diese flexible Sprache ebenso bewährt, wie im Bereich der technisch-wissenschaftlichen Software (Grafik, Prozeß-Steuerung, Simulation etc.) und der hardwarenahen Mikroprozessor-Programmierung.

Kein Wunder also, daß sich C auch im kommerziellen und administrativen Bereich immer größerer Beliebtheit erfreut und gerne als die beste prozedurale Hochsprache für die professionelle Softwareentwicklung bezeichnet wird. Die Gründe dafür sollen im folgenden etwas näher beleuchtet werden.

C unterstützt die strukturierte Programmierung

Die zentrale Idee der strukturierten Programmierung ist, durch die statische Notationsstruktur die Ablaufdynamik eines Programmes sichtbar zu machen.

C ist eine formatfreie Sprache und bietet alle Kontrollstrukturen, um Wiederholungen und Verzweigungen ohne Sprünge programmieren zu können.

Durch die Formatfreiheit ist der Programmtext nicht an bestimmte Spaltenpositionen gebunden, so daß der Programmierer geschachtelte Kontrollstrukturen - entsprechend der Idee der strukturierten Programmierung - frei einrücken kann. Daraus resultieren leicht lesbare Programmstrukturen, die Wartungsfreundlichkeit wird deutlich verbessert und Einarbeitungszeiten reduzieren sich.

C unterstützt die modulare Programmierung

Das Ziel der modularen Programmierung sind Programmsysteme, in denen logisch Zusammengehörendes (Typdefinitionen, Datendefinitionen, Funktionsdefinitionen, Makrodefinitionen etc.) in eigenen Quellcode-Modulen (Dateien) zusammengefaßt wird, die separat zu bindefähigen Objektcode-Modulen compiliert (und gegebenenfalls in Bibliotheken abgelegt) werden.

Das in der Sprachdefinition enthaltene Konzept der separaten Übersetzung einzelner Module ist so ausgelegt, daß es den Anforderungen des modernen Software-Engineerings entspricht: Alle für das Information-Hiding notwendigen Sprachmittel sind vorhanden.

Sicherlich, auch andere Hochsprachen sehen separate Übersetzung und die Benutzung von Bibliotheksfunktionen vor; aber in kaum einer sind diese Konzepte so flexibel und bequem realisiert.

Fünf wesentliche Vorteile bietet die modulare Programmierung ihren Anwendern.

- Werden die Module in eine hierarchische Dateistruktur richtig eingebettet, so lassen sich damit logische Abhängigkeiten zwischen den Systemteilen sehr gut zum Ausdruck bringen.

- Es ergeben sich leicht überschaubare Bearbeitungseinheiten. Das kommt der Effizienz des Programmierers zugute.

- Es lassen sich damit Module realisieren, die mehrfach verwendet werden können. Die Mehrfachverwendung kann innerhalb eines oder mehrerer Projekte erfolgen. Das arbeitsteilige Vorgehen erhöht die Effizienz des Teams.

- Hardwareabhängigkeiten lassen sich in definierten Modulen zusammenfassen. Damit werden Portierungsarbeiten vereinfacht.

- Über Bibliotheksmodule läßt sich die Sprache beliebig erweitern. Die selbst geschriebenen Bibliotheksfunktionen sind genauso einfach zu verwenden wie die mit dem Compiler standardmäßig gelieferten Funktionen. Auf dem Markt gibt es Dutzende von C-Bibliotheken mit allen möglichen Spezialfunktionen.

Der hohe Grad an sprachinhärenter Portabilität hat im wesentlichen seine Ursache in der umfassenden Sprachdefinition. Da der definierte Leistungsumfang der Sprache (Qualität und Anzahl der Kontrollstrukturen, der Datenstrukturen und der Operatoren) kaum Wünsche offen läßt, hat die Sprachdefinition (ursprünglich von den Sprachautoren Brian W. Kernighan und Dennis M. Ritchie, später durch den ANSI Standard X3J11) eine sehr hohe Akzeptanz gefunden: Es gibt praktisch keine Dialekte der Sprache.

Allerdings ist die Portabilität keine binäre Eigenschaft, die entweder vorhanden ist oder nicht. Sie ist ein Kontinuum: Von der hundertprozentigen Portabilität bis zur Unmöglichkeit einer Portierung sind alle Zwischenstufen denkbar. Letztendlich muß Portabilität bereits ein Entwurfsziel sein, will man die Sicherheit haben, daß sich die geschriebene Applikation später "leicht" auf andere Computer mit möglicherweise auch anderen Betriebsysstemen portieren läßt.

C unterstützt die defensive Programmierung

Unter Verzicht auf Kniffe und Tricks so zu programmieren, daß die resultierenden Programme hohen Sicherheitsanforderungen gerecht werden, bezeichnet man als defensiven Programmierstil.

Die Sicherheit einer Sprache wird im wesentlichen bestimmt durch ihre Strukturierungseigenschaften einerseits und andererseits durch ihre Typstrenge. Wie gut die Strukturierungseigenschaften einer Sprache sind, läßt sich an den verfügbaren Kontroll- und Datenstrukturen "messen". Mit Kontrollanweisungen, skalaren Datentypen, Kompositionstypen und der Möglichkeit, eigene Datentypen einzufahren, ist C reichlich ausgestattet, ohne jedoch Überflüssiges anzubieten.

Was die Typstrenge angeht, so bietet die Sprache alle notwendigen Variationsmöglichkeiten: Bei der Programmierung hardwarenaher Operationen ist es unerläßlich, die strenge Typisierung zu umgehen - C gestattet dies dem Programmierer auf einfache Weise, ohne daß er Kunstgriffe anwenden muß. Ist andererseits bei der Programmierung auf entsprechend hohem Abstraktionsniveau eine modulübergreifende, strenge Typisierung notwendig, so läßt sich auch dieses realisieren.

Weitere Kriterien, die Rückschlüsse auf die Sicherheit zulassen, sind Qualität und Quantität der Operatoren. In dem Maße, wie die Anzahl der Operatoren zunimmt, sinkt die Notwendigkeit, fehlende Operatoren durch trickreiche Programmierung zu ersetzen. Auch unter diesem Aspekt ist C bestens ausgestattet: Mit über vierzig Operatoren unterstützt C ein außerordentlich breites Applikationsspektrum.

Zu guter Letzt wird die Sicherheit eines Programms auch von seiner Lesbarkeit beeinflußt. Neben den von der Sprache angebotenen Strukturierungsmöglichkeiten prägt vor allem die Verwendung sprechender Namen die Lesbarkeit. Mit einer Länge von einunddreißig (gültigen) Zeichen für (interne) Namen sind hier dem Programmierer kaum Grenzen für eine aussagefähige Bezeichnungssystematik gesetzt.

C erlaubt einen kompakten Programmierstil

Durch eine Reihe von Spracheigenschaften fördert C einen kompakten Programmierstil: Der C-Programmierer muß im Vergleich zu den Anwendern anderer Hochsprachen (Ada, Basic, Cobol, Fortran, Modula-2, Pascal etc.) weniger schreiben. Die Quellprogramme sind kürzer, ohne daß die Lesbarkeit leidet.

Ursache dafür sind unter anderem die kurzen Sprachsymbole (so werden beispielsweise für die Blockklammerung statt "begin" und "end" die Symbole "{" und "}" verwendet), die mächtigen Operatoren (statt "a = a + 5" schreibt man kürzer "a + = 5") und die Möglichkeit, Seiteneffekte zu nutzen.

C ist eine mächtige Programmiersprache

C unterstüzt eine große Applikationsbandbreite. Programme auf hohem Abstraktionsniveau, ohne Berührungspunkte mit den Niederungen der Hardware lassen sich genauso elegant schreiben wie sehr hardwarenahe Routinen, die dem Computer das äußerste abverlangen.

Mit Hilfe von Zeigern (Pointer) lassen sich Speicherinhalte auf einfache Weise direkt bearbeiten. Das geht in C so leicht und flexibel wie in keiner anderen Sprache. Pascal bietet dem Programmierer ebenfalls Zeiger, doch sind die entsprechenden Sprachkonstrukte nicht so einfach und leistungsfähig wie in C. Der direkte Speicherzugriff in Basic mit PEEK und POKE erreicht die Flexibilität der C-Pointer bei weitem nicht.

Andere Maschinenresourcen, die sich sehr nutzbringend einsetzen lassen, sind die freien CPU-Register. Um beispielsweise Schleifen mit maximaler Geschwindigkeit zu fahren, definiert der C-Programmierer Registervariablen als Schleifenzähler. Damit werden Speicherzugriffe für die Schleifenzähler vermieden und so die Abarbeitung drastisch beschleunigt.

C-Programme sind schnell

Die folgende Tabelle gibt eine ungefähre Vorstellung von den Laufzeitunterschieden bei der Verwendung verschiedener Sprachen. Selbstverständlich kann ein solcher Vergleich keine absolute Qualifizierung von Sprachen sein. Da aber jede Sprache - unter dem Aspekt der Effizienz - nur so gut wie ihr Compiler beziehungsweise dessen Optimierer ist, soll diese Tabelle dennoch vorgestellt werden.

Alle marktgängigen C-Compiler sind mit Optimierern ausgerüstet. Dies sind in der Regel sogenannte lokale Optimierer oder Guckloch-Optimierer (peep hole optimizer) mit relativ beschränkten Möglichkeiten: innerhalb einer Funktion werden Anweisungssequenzen optimiert. Einen höheren Optimierungsgrad bieten globale Optimierer, die mit Hilfe der Datenflußanalyse versuchen, eine Funktion insgesamt zu optimieren.

Für den Löwenanteil aller Applikationen ist das Laufzeitverhalten der von C-Compilern und -Optimierern erzeugten Programme so gut, daß bei Entwurfszielen wie "Portabilität" und "klare Programmstruktur" nicht auf das Entwurfsziel "hohe Geschwindigkeit" verzichtet werden muß.

C ist industrietauglich

Alle bisher angesprochenen Eigenschaften der Sprache C spielen in allen Bereichen des industriellen Softwarebaus eine bedeutende, nicht zu überschätzende Rolle. Dem Hersteller von Standardpaketen dürfte die Portabilität am wichtigsten sein, denn er ist in aller Regel auf eine breite Marktbasis angewiesen. Es ist sicher eine gesunde Entscheidung, die Software-Investitionen nicht nur an die Marktpräsenz bestimmter Hersteller zu binden, sondern mit den vorhandenen Produkten auf eine möglichst breite Hardware-Palette unterschiedlicher Anbieter zu zielen.

Im Industriebereich der auf Mikroprozessor-Technik basierenden intelligenten Geräte, steigen die Investitionen in die Software-Entwicklung stetig. Um diese zu schützen, versuchen die Gerätebauer unter anderem durch den Einsatz einer geeigneten Programmiersprache sich ihre Unabhängigkeit vom Prozessor-Hersteller zu erhalten.

Angesichts des raschen Wandels in der Prozessortechnik sind die Software-Entwickler darauf bedacht, selbst technisch unabhängig zu bleiben. Es ist wirtschaftlich nicht vertretbar, bei einem Wechsel des Prozessors jeweils die gesamten Softwareinvestitionen aufzugeben, nur weil die vorhandenen Assembler-Programme nicht auf den neuen Prozessor portiert werden können.

Solche Inkompatibilitäten gibt es bereits zwischen den Prozessoren eines Herstellers und sie sind naturgemäß am größten, wenn mit dem Prozessorwechsel auch ein Herstellerwechsel verbunden ist.

Die Möglichkeit, auch in Zukunft den Hersteller seiner Mikroprozessoren frei wählen zu können, kann für den Produzenten intelligenter Geräte überlebensnotwendig sein: Um im Wettbewerb die Nase vorne zu haben, ist es von entscheidender Bedeutung, technisch führende Produkte einzusetzen, selbst dann, wenn sie nicht vom bisher bevorzugten Hersteller stammen.

Aufgrund der beschriebenen Eigenschaften ist C sicherlich eines der besten Mittel, sich gegen diese Probleme zu schützen. Nicht zuletzt deshalb ist ein anhaltender Trend in Richtung C zu beobachten.

C macht Programmierer flexibel einsetzbar

Obwohl C ursprünglich für das Betriebssystem Unix entworfen wurde, ist die Sprache längst hardware- und betriebssystemunabhängig geworden. Auf der Grundlage des Standards X3J11 des American National Standards Institute (ANSI) ist sie heute auf nahezu allen Betriebssystemen und Prozessoren verfügbar. Das bedeutet für den Programmier, daß er mit seinem erworbenen Wissen auf allen Computern und Betriebssystemen ohne lange Einarbeitungszeit kurzfristig produktiv werden kann.

C+ +, die objektorientierte Weiterentwicklung der Sprache, besitzt die gleichen Vorteile wie C - und darüber hinaus noch einige besondere Fähigkeiten (siehe Kasten). Um die speziellen Möglichkeiten der OOP zu realisieren, bedarf es nicht nur einer geeigneten Sprache, sondern auch einer geeigneten Mannschaft: Sie muß die objektorientierte "Denke" haben. Auch wenn der "klassische" C-Programmierer diese mit Sicherheit noch nicht hat - mit C + + ist eine Migrationsstrategie denkbar, die in vernünftiger Zeit und mit vertretbarem Budget realisierbar ist.

Ein Umstieg mit der gesamten Mannschaft auf eine andere objektorientierte Sprache - (wie Smalltalk oder Eiffel) käme bei höherem Risiko vermutlich wesentlich teurer.