Entwickler schwärmen von der Freiheit, die ihnen C läßt

Für die Programmierer ist C die Sprache der Zukunft

01.02.1991

Ist C unvermeidlich? Gehören C-Kenntnisse bereits zu den Voraussetzungen für eine DV-Karriere? Wer sollte wann - und wieso überhaupt - seine Programme auf C umstellen? Nach den eher allgemeinen und theoretischen Auslassungen der Schwerpunktbeiträge in der Ausgabe 1/91 melden sich hier nun die Praktiker mit ihren Erfahrungen zu Wort.

Dr. Axel Kemper

Space GmbH, Hannover

Die Programmiersprache C kann heute auf nahezu jedem Rechner eingesetzt werden und ermöglicht gerade auf der Systemebene das Schreiben von sehr effizienten Programmen. Die zunehmende Standardisierung (ANSI-C, X/Open Portability Guides etc.) erleichtert gegenüber der Urversion von Kernighan und Ritchie die Entwicklung von lesbaren und portablen Programmen.

Heute stehen leistungsfähige Bibliotheken und Entwicklungswerkzeuge zur Verfügung, die die Programmentwicklung enorm beschleunigen. C gehört zum Standardumfang von EDV-Ausbildungsgängen und wird durch eine Vielzahl von Fachbüchern Studenten und Praktikern nahegebracht.

Wie und wofür wird C bei uns eingesetzt?

Bei uns wird C in der Systemprogrammierung, für die Kommunikationstechnik, für Projekte im Bereich Betriebsdatenerfassung (BDE) und für die Programmierung von Kassensystemen eingesetzt. Hardwareplattformen sind Unix-Rechner und Workstations (Siemens MX300/MX500 und WX200), Personal Computer, Siemens Großrechner unter BS2000, BDE-Controller und Kassen.

Bei der Entwicklung hat es sich in vielen Fällen bewährt, Module zunächst auf einem PC zu entwickeln und dann auf den Zielrechner zu sortieren. Vorteile der C-Entwicklungssysteme auf PCs sind ihre enorme Compilier-Geschwindigkeit, die Einbindung leistungsstarker Texteditoren und die komfortablen Source-Code-Debugger. Sie erleichtern die Arbeit so sehr, daß der Portierungsaufwand nicht mehr ins Gewicht fällt.

Moderne C-Compiler sind mit Hilfe von Prototypdefinitionen in der Lage, detaillierte Fehlerprüfungen vorzunehmen. Dafür brauchte man früher spezielle Prüfprogramme (Lint).

Kontextsensible Hilfe-Systeme erlauben dem Entwickler, aus dem Editor heraus auf Knopfdruck Informationen zu Bibliotheksroutinen, zur Sprache selbst und zur Entwicklungsumgebung abzufragen. Hilfsprogramme zur automatischen Neu-Übersetzung geänderter Module (Make) und zur Ermittlung zeitkritischer Programmteile (Profiler) stehen nicht nur unter "großen" Unix-Systemen, sondern auch auf PCs zur Verfügung.

Die Space GmbH setzt die Benutzeroberfläche OSF/Motif auf X/Windows-Terminals und WX200-Workstations von Siemens ein. Die entsprechenden Bibliotheken erfordern zur Zeit C als Programmiersprache.

Für Informationssysteme, die mit Hilfe von Menüs und Masken den Zugriff auf Datenbanken realisieren, verwenden wir die 4GL-Entwicklungsumgebung "Miracle". Hier werden lediglich Schnittstellenprogramme in C programmiert.

Unternehmenspolitische Aspekte beim C-Einsatz

In unserem Unternehmen sind Funktionssicherheit, Effizienz, Wartbarkeit, Portabilität, Wiederverwendbarkeit und Lesbarkeit die wichtigsten Aspekte bei der Software-Entwicklung. Bei konsequenter Beachtung von Programmier- und Dokumentationsrichtlinien lassen sich diese Kriterien mit C besser erfüllen als mit Konkurrenzsprachen wie Assembler, Pascal, Modula-2 oder Fortran.

C bietet mit der Weiterentwicklung C + + Zukunftsperspektiven und ermöglicht den Zugang zu modernen Programmiermethoden.

Sind C-Kenntnisse heute eine Karrierebedingung?

Wohl keiner, der heute eine EDV-Ausbildung durchläuft, wird um C herumkommen. Dennoch kann man auch ohne entsprechende Kenntnisse Karriere machen. Technische und betriebswirtschaftliche Erfahrungen und der sichere Blick für den richtigen Algorithmus am richtigen Platz sind wichtiger als das reine Programmierwissen. Zu bedenken ist auch, daß C keine Programmiersprache für Anfänger oder "Gelegenheitsprogrammierer" ist. Man sollte vorher schon in Pascal, Modula oder Assembler Erfahrungen gesammelt haben.

Neben den reinen Programmierkenntnissen gewinnt der Umgang mit professionellen Entwicklungsumgebungen immer mehr an Bedeutung und sollte dementsprechend schon in der Ausbildung vermittelt werden.

Michael Bormann

Nielsen CMS GmbH, Frankfurt/Main

Nachdem C lange Zeit im verborgenen, vornehmlich auf Unix-Systemen, zu Hause war, hat die Sprache mittlerweile im Bereich MS-/PC-DOS eine unübersehbare Verbreitung gefunden. Dieser vermeintlich plötzliche Wandel ist nicht so verwunderlich, wie es scheint. Die verfügbaren Werkzeuge sind in den letzten Jahren immer besser geworden und nun auch für Einsteiger geeignet. Was zu Anfang noch abschreckend und kompliziert wirkte, erscheint heute wie aus einem Guß. War anfangs für den Hobbyprogrammierer ein "richtiger" C-Compiler finanziell kaum zu verkraften, braucht er heute mit den Quick- und Turbo-Produkten nicht mehr abseits zu stehen. Daß mit ihnen die Neugier auch bei schmalem Budget gestillt werden kann, ist einer der Gründe für die gewaltige Verbreitung, die C momentan erfährt.

Im Gegensatz zum privaten Bereich war bei den mit C liebäugelnden Betrieben nicht der Preis das Problem. Hier gibt oder gab es völlig andere Kriterien, die einen Wechsel nach C verhinderten oder zumindest erschwerten. Heute jedoch kann man sagen, daß eine Investition in diese Richtung sich allein schon wegen der besseren Portierbarkeit der entwickelten Software rechnet.

Wann lohnt es sich, auf C umzusteigen?

Eine generelle Regel für den richtigen Zeitpunkt zum Umstieg gibt es nicht, wohl aber Kriterien, die bei der heutigen Situation eindeutig für C sprechen. Zum einen ist es eine Frage der Zieloberfläche, etwa Unix/Xenix, DOS/Windows oder auch OS/2, zum anderen eine Frage der Anwendungsgebiete.

Bei Unix oder Xenix ist die Sachlage fast eindeutig: Hier wird so gut wie ausschließlich in C entwickelt. OS/2-Entwickler sind ebenfalls mit C gut beraten, besonders wenn Presentation-, Database- oder LAN-Manager direkt angesprochen werden sollen. Auch für Windows-Applikationen bietet sich C als die problemloseste Sprache an, und wer Entwicklungen oder Erweiterungen für Netware 286/386 plant, wird um C ebenfalls nicht herumkommen.

Tatsache ist, daß die heute auf dem Markt befindlichen dominanten Betriebssysteme und Oberflächen vornehmlich Schnittstellen zu C anbieten. C ist keine Modeerscheinung mehr, auch wenn sich möglicherweise schon die Fortentwicklung zu C + + abzuzeichnen beginnt. Wer diese Oberflächen in sein Konzept einplant und eigene Anwendungen entwickelt, dem bleibt keine andere Wahl, als sich mit C vertraut zu machen.

C ist eine Sprache ohne Schnörkel

Der verbreiteten Meinung, C sei eine schwierige Sprache, sollte man hier einige Fakten entgegenstellen. Es gibt kaum eine Sprache außer Assembler, die den Programmierer so wenig einschränkt. C ist eine Sprache ohne Schnörkel und mit wenigen Konventionen. Beispielsweise ist nicht verboten, mit Buchstaben zu rechnen (wie es häufig praktiziert wird, um aus Großbuchstaben Kleinbuchstaben zu machen). Der Einsatz der vielbeschriebenen Zeiger ist in ungeübter Hand gelegentlich etwas wild, ermöglicht aber eine sehr effiziente und übersichtliche Programmierung.

Ein Programmierer, der von Pascal nach C wechselt, wird schon nach kurzer Zeit die neue Freiheit entdecken und nutzen. Umgekehrt fühlt sich ein C-Programmierer nicht selten von anderen Sprachen in seiner Kreativität eingeschränkt.

Die ersten Erfahrungen mit neuen Methoden sind in aller Regel mühsam, bis sich das Verständnis dafür entwickelt hat. Heutzutage gibt es als erste Hilfe zur Portierung Konvertierungsprogramme, die Pascal- und sogar Basic-Sourcen in C-Code umwandeln. Damit ist es wesentlich einfacher geworden, vorhandene Pakete zu adaptieren.

Für Anwendungen unter Windows existiert eine Reihe von Code-Generatoren, die ein funktionsfähiges Gerüst erstellen. Selbstverständlich beinhaltet dieses Gerüst nur die spezifischen Funktionen zur Fenster- und gegebenenfalls Maskenverwaltung. Nacharbeit ist auf jeden Fall erforderlich, und das oft nicht zu knapp. Hierfür wird dann selbstredend ein C-Kundiger benötigt, der ebenfalls einige Erfahrung in der Window-Programmierung aufweisen sollte.

Problematisch wird es, wenn ein über Jahrzehnte gepflegtes und ergänztes Programm, in Cobol beispielsweise, nun unter Windows verfügbar sein soll. Allein die Portierung in eine andere Sprache reicht schon aus, um das Vorhaben für undurchführbar zu erklären. Besser ist hier allemal eine komplette Neuentwicklung, zumal dann einige Dinge von vornherein besser gemacht und die im Ursprungsprogramm undurchführbar gewordenen Ergänzungen gleich in das Konzept eingeplant werden können. In jedem Fall ist ein detailliertes Pflichtenheft neben einem erfahrenen C-Programmierer unerläßlich, wobei letztere aufgrund des C-Booms, besonders für Windows oder OS/2, rar geworden sind. Wünscht man die Vorteile der nun verfügbaren einheitlichen Oberfläche von Windows 3.0 und der damit verbundenen Möglichkeiten - wie Austausch von Bildschirminhalten, DDE (Dynamic Data Exchange), Grafiken, DTP und nicht zuletzt mehr Arbeitsspeicher und verbessertes Netzwerk-Handling - ist der Umstieg auf C fast zwingend.

Skeptisch sollte man gegenüber der Aussage sein, mit C wäre alles machbar. Wie die vorhandene Software zeigt, stimmt das zwar, aber es bleibt immer die Frage, ob eine konkrete Aufgabe nicht besser in einer anderen Sprache erledigt wird. Niemand hindert einen daran, bestimmte Routinen in Cobol, Pascal oder auch in Fortran zu schreiben, denn die heutigen Compiler beinhalten alle die Möglichkeit, Fremdsprachen zu integrieren.

Erich Neuhauser

Ensoft GmbH, Dietzenbach

Was C so attraktiv macht, ist das breite Spektrum, das mit dieser Sprache im Vergleich zu allen anderen abgedeckt werden kann. Nach "unten" helfen einige spezielle Befehle, sowie (meist) zum Compiler gehörende Optimierungsprogramme, die Effektivität von Assembler-Programmen zu erreichen und in Sonderfällen sogar zu übertreffen. Nach "oben" verfügt C über Erweiterungs- und Anpassungsmechanismen, die in jedem Bereich mindestens ebensoviel "Problemorientierung" ermöglichen, wie jede andere höhere (prozedurale) Programmiersprache.

Die Flexibilität und Offenheit nach "oben" geben dem C-Programmierer eine Garantie für die Zukunft. Gleichzeitig ist es, wie stets in der EDV: Die Flexibilität enthält den Keim des Chaos. Nur sorgfältige Planung und selbstgewählte Beschränkung garantieren den Genuß ohne Reue.

Zu den Entscheidungen, die man am längsten bereuen kann, zählt die Auswahl von Funktionsbibliotheken. Im Konzept von C spielen "Functions" eine zentrale Rolle. Eine Funktion ist eine Unterroutine, deren Aufruf etwa so aussieht:

TAGE = TAGES_DIFFERENZ

(ANF_DATUM, END_DATUM)

Die Funktion TAGES_DIFFERENZ errechnet die Anzahl der Tage zwischen zwei Datumsangaben und liefert das Ergebnis zurück. Anstatt das Ergebnis der Variablen TAGE zuzuordnen, könnte man es auch gleich weiterverwenden:

LOHN = TAGES_LOHN *

TAGES_DIFFERENZ

(ANF_DATUM, END_DATUM)

Die Unterroutine TAGES_DIFFERENZ kann entweder zusammen mit dem übrigen Programm im Quellcode vorliegen, oder sie kann bereits früher compiliert und als ausführbares Objekt in einer Funktionsbibliothek untergebracht worden sein. Der Aufruf ist in beiden Fällen gleich!

Dieser elegante und überschaubare Mechanismus funktioniert in der Programmierpraxis wie eine Erweiterung des eigentlichen Befehlssatzes und wirkt sich in zwei Richtungen aus. Zum einen konnte der vorgegebene Sprachkern von C sehr klein gehalten werden. Sämtliche I/O-Funktionen, höhere mathematische Funktionen und vieles mehr wurden als Bibliotheksfunktionen realisiert (was natürlich bedeutet, daß zum Lieferumfang eines C-Compilers stets auch eine Funktionsbibliothek gehört). Andererseits eröffnet dieser Mechanismus auch jedem Anwender die Möglichkeiten zur "Spracherweiterung".

Der Übergang zwischen der programmspezifischen Unterroutine und der Bibliotheksfunktion ist fließend und kann jederzeit vollzogen werden. So kann der Sprachumfang von C bei Bedarf um Problem- oder anwendungsorientierte Funktionen erweitert werden. Daraus ergibt sich zum einen die Zuversicht der C-Fans, nie an Grenzen stoßen zu können, die im Sprachumfang begründet sind. Andererseits erhalten gewohnheitsmäßig benützte Funktionen letztlich den Status von Bestandteilen der Sprache C. Es ist daher nötig, bei der Auswahl von Funktionsbibliotheken mit größter Sorgfalt vorzugehen.

Funktionsbibliotheken kann man für die Praxis in drei Gruppen einteilen, nämlich Standardbibliothek(en) des Compiler-Herstellers, spezielle Bibliotheken von anderen Anbietern und Sammlungen eigener Funktionsroutinen.

Der Einsatz von Bibliotheken

Die zum Lieferumfang des Compilers gehörenden Bibliotheksfunktionen sind zunächst unverzichtbar, weil C selbst beispielsweise keinerlei Ein- und Ausgabe-Befehle enthält. Wie weit man diese Funktionen einsetzt, sollte man von ihrer Übereinstimmung mit der ANSI-Norm abhängig machen. Ungenormte E/A-Funktionen einzusetzen bedeutet automatisch, hersteller- oder systemabhängig zu werden.

Der Einsatz weiterer Bibliotheken hängt von der Aufgabenstellung ab. Angeboten werden beispielsweise Bibliotheken mit Grafikfunktionen oder mit ISAM-Funktionen. Die Anschaffung solcher Bibliotheken ist nur dann empfehlenswert, wenn der Quell-Code im Lieferumfang enthalten ist. Nur dann nämlich besteht die Chance zu einem Systemwechsel, der ja stets früher als geplant nötig wird. Darüber hinaus sollten derartige Bibliotheken ihrerseits möglichst systemunabhängig sein (in manchen Fällen, etwa bei hardwarenahen Funktionen, ist diese Forderung allerdings nicht zu erfüllen).

Lösungen immer wieder verwenden

Schließlich entstehen bei der praktischen Arbeit immer wieder Routinen, die auch in anderen Programmen sinnvoll einsetzbar sind. Man faßt sie mit Hilfe von Werkzeugen des Compiler-Herstellers zu Bibliotheken zusammen, in denen aufgaben- oder sogar unternehmensspezifische Lösungen zu finden sind.

Die Erstellung universell einsetzbarer Funktionsroutinen erfordert einige Erfahrung, doch diese Erfahrung entsteht fast automatisch, weil das Schreiben einer Funktion eben identisch ist mit dem Schreiben einer Unterroutine. Gerade hier ist sorgfältige Planung wichtig, weil universelle Funktionen vom Programmierer als Sprachbestandteile "adoptiert" werden und sich nach einiger Anwendungszeit nur noch unter Schwierigkeiten ersetzen oder verändern lassen.

Der Vollständigkeit halber sei erwähnt, daß das Funktionenkonzept von C sowohl durch einen vorgelagerten Makro-Prozessor unterstützt werden kann als auch durch die Möglichkeit, Datentyp-Prüfungen für Funktionsaufrufe vorzugeben. Im Gegensatz zu manchen Gerüchten nämlich ist C sehr wohl eine typenstrenge Sprache - sofern man diese Eigenschaft nicht bewußt umgeht.

Unsere Erfahrung mit dem Mechanismus der Funktionsbibliotheken in C ist grundsätzlich sehr positiv. Wir benützen C sowohl zur Herstellung kommerziell orientierter Basissoftware (zum Beispiel Massendatenerfassung) im PC-Bereich als auch für Individualprogramme. Unterschiedlichste Aufgaben im kommerziellen Bereich konnten auf diesem Weg effektiver gelöst werden als mit anderen Sprachen. Dabei erzeugten wir neben Funktionen zur Bearbeitung von Zeichenfeldern einschließlich ASCII-Arithmetik auch Funktionen zur bedienerfreundlichen Bildschirmprogrammierung, die ja in den meisten gängigen Programmiersprachen fehlen.

Unangenehme Erfahrungen machten wir mit den E/A-Funktionen des Compiler-Herstellers. Obwohl die Konformität mit ANSI-C zunächst für diese Funktionen sprach, zeigte sich, daß die Behandlung von Fehlerzuständen für unsere Zwecke nicht ausreichte. Im PC-Bereich ist der Anwender selbst für die Behebung vieler Fehlerzustände verantwortlich (Diskette fehlt, Drucker offline etc.) und benötigt etwas mehr als nur die lapidaren Aussagen von MS-DOS. Auch werden die Fehlermeldungen von MS-DOS ohne Rücksicht auf vorhandene Bildschirminhalte in Fernschreiber-Manier auf den Bildschirm geschrieben.

Wir entschieden uns, über die vorhandenen System-Schnittstellen eigene E/A-Funktionen zu entwickeln, und konnten bei dieser Gelegenheit auch gleich zusätzliche Funktionalität realisieren (satzorientierten Zugriff und ISAM).

Unser aktueller Stand ist eine in den meisten Bereichen wesentlich gesteigerte Produktivität, eine optimale Anpassung des Sprachumfanges an unsere Aufgabenstellungen, eine fast grenzenlose Flexibilität und eine minimale Systemabhängigkeit, die sich auf exakt definierte Bereiche beschränkt. Ebenfalls exakt zu definieren ist die einzige Schwäche des Konzepts, nämlich die Abweichung der "privaten" Funktionen vom Standard, die wir durch sorgfältige Dokumentation ausgleichen. Dabei handelt es sich natürlich um keine echte Schwäche, sondern um einen Aspekt der Stärke, die im Funktionenkonzept von C liegt.

Fazit für potentielle Überläufer: Die Einführung von C dauert schon deshalb etwas länger als bei anderen Sprachen, weil sich der tatsächlich verwendete Sprachumfang erst nach und nach herauskristallisiert. Man sollte deshalb entweder früher anfangen oder bis zum ersten Ergebnis mehr Geduld haben.

Robert Jones

Unternehmensberatung, Dortmund

Die Programmiersprache C ist ein mächtiges Instrument zur Software-Entwicklung. Die Datenstrukturen, die sich in C bauen lassen, sind für die gute Organisation eines Programmes

ebenso wichtig wie die ausführbaren Anweisungen. Das kommt besonders bei großen Datenbank-Anwendungen zur Geltung.

Peter Chens Entity-Relationship-Modell für Datenbanken geht von vier Arten der Datenverknüpfung aus: 1 zu 1, 1 zu N, M zu 1, und M zu N. Alle diese Verknüpfungen lassen sich in C realisieren, verwalten und durchsuchen. Wesentliches Hilfsmittel dabei sind selbstdefinierte Datentypen und Datenstrukturen.

Die Definition wie auch die Verwaltung von Datenstrukturen läßt sich elegant über den Makro-Preprozessor des C-Compilers abhandeln. Die benötigten Makros kann man entweder selbst entwickeln oder einer gekauften Makro-Library (es gibt sie von verschiedenen Software-Anbietern) entnehmen. Zur Realisierung der Verknüpfungen, die im Modell von Chen vorgesehen sind, sind vier Makros erforderlich:

ORG_1_TO_1

ORG_1_TO_N

ORG_M_TO_1

ORG_M_TO_N

Der Vorteil bei der Benutzung von Preprozessor-Makros liegt in der einheitlichen Handhabung wiederverwendbarer Datenstrukturen. Die obigen Makros können entweder als Schnittstelle zu einer relationalen Datenbank oder als Schnittstelle zu C-Datenstrukturen, die mit Zeigervariablen verknüpft sind, verwendet werden. In der folgenden Beschreibung wird angenommen, daß sie zur Definition von Datenstrukturen über Zeigervariablen benutzt werden.

Die Wiederverwendbarkeit der Definitionen in der Form von Preprozessor-Makros erlaubt auch die Verwendung von Makros zum Durchsuchen einer Datenstruktur, zu ihrer Verwaltung sowie zum Hinzufügen und Löschen von Datenelementen.

Weitere Makros im ausführbaren Teil des C-Programms verarbeiten dann die Strukturen, die in den obigen Makros definiert wurden, zum Beispiel:

ALLOC: Reserviert Speicherplatz für einen Block von Daten mit Zeigern.

ADD-SINGLE: Fügt einen Block in eine Struktur ein.

DELETE: Löscht einen Block.

TRAVERSE: Durchsucht einen Block.

CLEAR: Entfernt einen Baum von Blöcken aus dem Speicher.

SAVE: Sichert einen Block auf Festplatte.

Wichtig hierbei ist, daß C-Zeigervariablen dem Programmierer transparent bleiben.

Die saubere Organisation von Programmen durch strukturierte Programmierung ist inzwischen gut bekannt. Weniger geläufig ist die sorgfältige Strukturierung von Daten.

Zeigervariablen sind die für C natürliche Weise des Umgangs mit Datenstrukturen. Gerade bei komplizierten Datenstrukturen zeigen sich die umfangreichen Verarbeitungsmöglichkeiten, die C damit besitzt.

Allerdings können Zeigervariablen und Datenstrukturen auch zum Verhängnis der Software-Entwicklung werden: Eine Vielzahl sehr verwickelter Zeigervariablen kann zu "Spaghetti-Daten" führen. Die ordentliche Wiederverwendbarkeit von Datenstrukturen nimmt deshalb einen besonderen Stellenwert bei der Software-Entwicklung in C ein. Unvorsichtige Anwendung von Zeigervariablen kann zu Fehlern führen, deren Behebung viel Zeit kostet. Dagegen kann die Normierung der wiederverwendbaren Datenstrukturen mit Hilfe von Makros, die sie definieren und verarbeiten, die Verwendung der Zeigervariablen übersichtlich und transparent machen. Sauber konzipierte und klar organisierte Datenstrukturen vereinfachen damit auch den ausführbaren Teil des Programms.