C (Programmiersprache)
Die Programmiersprache C wurde von Ken Thompson und Dennis Ritchie entworfen, u.a. um Unix portabel aber trotzdem systemnah zu programmieren. Die Programmiersprache 'B', der viele grundlegende Merkmale von 'C' entstammen, wurde zuvor von Ken Thompson entworfen. Die grundlegenden Programme aller Unix-Systeme und die Kernel vieler Betriebssysteme sind in 'C' programmiert.
'C' ist eine Programmiersprache, die auf fast allen Computersystemen zur Verfügung steht. Im Gegensatz zu z.B. BASIC gibt es seit der Definition von ANSI-C relativ einheitliche Implementationen auf den verschiedenen Plattformen. In jedem C-System steht auch die genormte Standard C Library zur Verfügung. Dies und die sehr gute Performance der resultierenden Programme erklärt die weiterhin relativ hohe Popularität der Sprache, sowohl im kommerziellen als auch im Open-Source-Bereich.
Softwaretechnologisch gesehen entspricht die Sprache nicht dem heutigen Stand der Technik und auch als portabler Highlevel-Assembler bezeichnet. Nachfolger sind die objektorientierten Sprachen C++, Java und C#, die C in Bezug auf Wartbarkeit, Produktivität, Entwurfsunterstützung, Abstraktionsniveau, geringerer Fehleranfälligkeit, betriebssystemunabhängiger Ablauffähigkeit und Leistungsfähigkeit der zugehörigen Bibliotheken teilweise eklatant ausstechen. Heutzutage wird praktisch keine Literatur mehr veröffentlicht, die sich noch mit C alleine (ohne C++) beschäftigt. Nichtsdestotrotz wird C auch langfristig in speziellen Einsatzgebieten erhalten bleiben.
Die Sprachbeschreibung wurde 1972 erstmals publiziert.
Ein ausführbares C-Programm wird durch den so genannten Linker aus Objektcode erzeugt (gebunden). Die Objektcodedateien ihrerseits werden durch den Compiler aus Textdatei(en) erzeugt (übersetzt), die eine Anzahl Funktions- und Variablendefinitionen enthalten. Ein ausführbares Programm muss eine Funktion mit dem Namen main enthalten.
"Hello, World!"-Programm in C
Der folgende Code stellt ein minimales C-Programm dar, das eine Meldung auf dem Standardausgabemedium ausgibt.
#include <stdio.h>
int main (void) { puts ("Hello, World!"); return 0; }
If ... else
if (Bedingung) { Anweisungen; } [else { Anweisungen; }]
While-Schleife
while (Bedingung) { Anweisungen }
Do ... while
do { Anweisungen } while (Bedingung);
For-Schleife
for (Startausdruck; Bedingung; Inkrementierausdruck) { Anweisungen }
Switch-Ausdruck
switch (Ausdruck) { case marke1 : Anweisungen; break; case marke2 : Anweisungen; break; default : Anweisungen; }
Siehe auch: C++, Objective-C, GCC, Zeittafel der Programmiersprachen
Schwächen von C
"Der Vorteil einer echten höheren Programmiersprache, und dazu zähle ich C nicht, ist der, daß die Sprachregeln vom Compiler überprüft werden können ..." (Nicolaus Wirth).
fehlende Objektorientierung
Der Sprachumfang von C unterstützt die objektorientierte Programmierung nicht.
leistungsschwache Bibliotheken
Wer professionell mit C arbeiten will, kommt mit den dürftigen Bibliotheken in aller Regel nicht aus.
mangelhafte Stringunterstützung
Den Typ String (Zeichenkette) gibt es nicht im Sprachstandard. Ersatzweise existiert eine Konvention, wie man mit Zeichenketten umgeht und eine begrenzte Zahl von Funktionen der Standard-C-Bibliothek, die diese Konvention umsetzt (strlen, strcpy, strcat, strchr, sprintf und andere). Die Konvention besteht darin, dass für einen String ein Character-Array verwendet werden und das Ende des Strings durch einen Nullcharcter gekennzeichnet wird. Man ging dabei von der Annahme aus, dass dieser in Zeichenketten nicht vorkommt.
unbekannte Arraylängen
Arrays werden an Funktionen als Pointer (Zeiger) übergeben. Innerhalb der Funktion ist dadurch die Länge des Arrays nicht mehr bekannt und ein Überschreiben von Speicher ohne weiteres möglich. Die Folge sind schwer zu diagnostizierende achitekturabhängige Fehler.
"wilde" Pointer
Man kann Pointer auf beliebige Stellen des Speichers richten. Insbesondere zeigen nicht explizit initialisierte Stack-Variablen oft auf beliebige Stellen des Speichers. Die Folge sind schwer zu diagnostizierende Fehler.
Speicherverwaltung
Der Programmierer muss den dynamischen Speicher selbst verwalten. Beim Zugriff auf dynamischen Speicher muss der Programmierer selbst wissen, welcher Datentyp wo abgelegt wurde. Es gibt keine Destruktoren und es werden Speicherbereiche nicht freigegeben, wenn die Lebensdauer ihrer Variablen abgelaufen ist.
Portabilitätsprobleme
Die Längen (sizeof) verschiedener Typen sind in der Sprachdefinition nicht vorgeschrieben. So ist z.B. nur zugesichert, dass ein short int wohl nicht länger sein wird als ein long int. Auch die wichtige Länge von Pointern und der Ergebnistyp von Pointerdifferenzen liegt nicht fest. Daher ist eine Portierung auf andere Systeme, insbesondere auf 64-Bit-Architekturen oft mit einigem Aufwand verbunden.
Ein weiteres schwerwiegendes Problem ist die Existenz von little Endian und big Endian Maschinen; Zahlentypen können nicht ohne weiteres auf andere Architekturen übertragen werden.
Schließlich ist auch das Alignment einer structure nicht in der Sprache definiert, so dass Structures auf verschiedenen Architekturen sogar unterschiedliche Größen im Speicher belegen.
Literatur
- The C Programming Language, Brian W. Kernighan and Dennis M. Ritchie. Prentice Hall, Inc., 1988., ISBN 0-13-110362-8 (paperback), ISBN 0-13-110370-9 (hardback).
- Deutscher Titel: Programmieren in C, Hanser, ISBN 3-446-15497-3