Diskussion:C (Programmiersprache)
Angebliche Mehrdeutigkeit
Der Ausdruck
a = b++ * ++b * b
ist nach den Precedenceregeln eindeutig: der Post- resp. Preincrement-Operator ++ hat eine höhere Precedenz als die Multiplikation *. Allerdings ist der Postincrement-Operator dadurch definiert, daß er den ursprünglichen Wert liefert und erst nach kompletter Auswertung des Ausdruckes auf sein Argument angewandt wird.
Die Multiplikation ihrerseits assoziiert von links nach rechts (die Increment-Operatoren von rechts nach links).
Voll ausgeklammert ergibt sich daher folgender Ausdruck:
a = (b++ * ++b) * b
Das obige Beispiel wird also wie folgt ausgewertet werden:
Schritt 1a: Auswertung des 1.Increment-Operatoren:
b++ -> b'=(b+1)
unter Beibehaltung des Originalwertes von b für die Berechnung des Gesamtausdruckes!
Schritt 1b: Auswertung des 2.Increment-Operators:
++b -> b"=(b'+1)
unter Ersetzung von b durch (b+1) für die Berechnung des Gesamtausdruckes!
Schritt 2: Auswertung der Multiplikation:
((b+1) * (b+1)) * (b+1)
Schritt 3: Ersetzen von b durch den Zwischenwert b":
b = b+2
Als Gesamtergebnis bekommt man also:
a=(b+1)*(b+1)*(b+1); b=b+2;
MikeTheGuru 16:57, 24. Feb 2004 (CET)
- Wenn du die Information aus der Sprachspezifikation hast, dann nimm doch meinen Absatz raus, bzw. korregiere ihn entsprechend.Ich hab im Moment keine Unterlagen da, um deine Aussage zu be- oder widerlegen, da meine Buecher bereits den Umzug gemacht haben. Kann sein, dass ich aus dem Kopf ein falsches Beispiel gewaehlt habe, ich hatte aber zumindest vor ein oder zwei Jahren selbst ein Bespiel gesehen, wo sich die Reihenfolge der Auswertung von gcc 2.95 auf gcc 3.0 geaendert hatte, nur hab ich im Moment keine Aufzeichnungen parat, wie das genau war. Michael 09:09, 25. Feb 2004 (CET)
- Die Frage ist auch, ob man diese Unvollständigkeit der Sprachdefinition unter Schwäche einordnen muss. Die Unbestimmtheit der Reihenfolge ist doch Teil der Sprachdefinition und dort ausdrücklich erwähnt. Sie ist also absichtlich vorhanden und resultiert in einfacheren Compilern und größeren Optimierungsmöglichkeiten. Schon K&R behandelt das Thema, es wurde also nicht ignorierrt oder gar vergessen. Auch, dass die Allozierung von Speichern oder das Datentyplayout nicht vorgeschrieben ist, ist Teil der Sprachdefinition und absichtlich. Also das Wort unvollständig trifft hier m.E. überhaupt nicht!!! Hierfür gab es Gründe. Das sind keine Schwächen. Hubi 09:24, 25. Feb 2004 (CET)
- Zumindest nicht gegebene Auswertereihenfolge ist ein Problem bei der Portierung - wie oben gesagt, ich hab irgendwo ein Beispiel rumliegen, wo sich das Verhalten von gcc-2.95 auf 3.0 geaendert hat - und das wohl auch ganz legal geaendert hat. Wenn du sowas hast, ist das Ergebnis eines Ausdrucks einfach "unbestimmt" und das ist eben etwas, dass du eigentlich nicht brauchen kannst - was hilft dir optimaler Code, der auf jeder Plattform andere Rechenergebnisse bringt? Es ist ein Nachteil, ja. Es ist eine bewusst in Kauf genommene Schwaeche - man kann eben nicht immer alles in allen Punkten optimieren. Und hier hat man sich eben fuer Flexibilitaet des Compilierbauers zulasten der Exaktheit der Sprache entschieden. Java geht den Weg genau anders rum, und mittlerweile scheint das bischen Overhead, das dadurch teilweise entsteht, nur noch wenigen weh zu tun. Michael 12:05, 25. Feb 2004 (CET)
- Wenn ich mich dann auch mal einklinken dürfte... Probleme mit Ausdrücken wie "a = (b++ * ++b) * b" sind keine Schwäche der Sprache, sondern des Programmierers, der so einen Müll schreibt. Was hilft es, wenn das genau in der Sprachspezifikation definiert ist, es aber niemand mehr entziffern kann ohne erst mal ne Viertelstunde irgendeine Spezifikation zu wälzen? Wenn ich als Programmierer die Absicht eines Ausdrucks nicht eindeutig entziffern kann, hilft es nichts, wenn es der Compiler kann. IMHO sollte der ganze Abschnitt 4.1 wg. massiv NPOV restlos gestrichen werden, außer es kommt ein ernsthaftes, sinnvolles Beispiel. --Andreas B. 18:56, 26. Feb 2004 (CET)
Der Artikel ist nicht NPOV (dürftige Bibliotheken, keine Überprüfung, keine Objektorientierung). C wurde als Sprache zur Implementation eines Betriebssystems (UNIX) definiert und 1972 publiziert. Selber schuld, wenn man's für andere Zwecke einsetzt. Die Kritikpunkte können zwar erwähnt werden, aber dringend umformulieren! Hubi 09:34, 8. Feb 2004 (CET)
Ich schliesse mich Hubi's Kritik an - es sind teilweise auch einige falsche Informationen in dem Text:
- fehlende Objektorientierung: Es ist zwar wahr, dass der Sprachumfang von C Objektorientierung nicht in der Form unterstuetzt wie es z.B. C++ oder Java macht, aber es ist sehr wohl moeglich, in C objektorientiert zu programmieren - Vererbung, virtuelle Methoden und aehnliche Konzepte aus der OOP koennen sehr einfach nachgebaut werden.
- Leistungsschwache Biblitheken? Was bitte soll das denn heissen? Das Statement als solches ist eine Beleidigung all jener Leute, die C-Bibliotheken programmieren und verbreiten.
Zusaetzlich kommen die wirklichen Schwaechen von C - wie z.B. Unbestimmtheit von bestimmten Ausdruecken - nicht im Artikel vor. Michael 11:42, 9. Feb 2004 (CET)
Zur Bemerkung von Michael über OOP: OOP ist ja eben eine "Methode für das Strukturieren von Software" (siehe Objektorientierte Programmierung) und keine Spracheigenschaft. Daher hatte ich auch den Satz "C ist nicht objektorientiert" rausgenommen und durch "C unterstützt OOP nicht" ersetzt, weil meiner Meinung nach eine Programmiersprache nicht objektorientiert sein kann; vielmehr kann die Sprache objektorientierte Programmierung unterstützen. Und das macht doch eigentlich C wirklich nicht, oder!? Keine Vererbung, Klassen, etc., d.h. mens muß den ganze OOP-Krempel selbst codieren. (Das es geht ist ja, wie gesagt, nicht die Frage!)
(BTW: Wenn ich Recht habe, müßte sich auch unter echtem Ur-BASIC objektorientiert programmieren lassen! ;-) Ralf 12:49, 9. Feb 2004 (CET)
- Na ja, sowas wie struct und Zeiger auf Funktionen werden schon benötigt, d.h. BASIC genügt wohl nicht. Aber Gnome-GTK und das Virtual File System im Linux-Kernel sind konkrete Beispiele in vielfachem Einsatz, wie man sowas unter C hinbekommt. Und der alte cfront von AT&T setzt auch nur C++ in C um. Hubi 13:12, 9. Feb 2004 (CET)
Ich finde, jemand sollte auch einen Abschnitt zu den Stärken von C schreiben, nur die Schwächen aufzulisten ist ja wohl kaum NPOV. -- 195.33.105.17 17:13, 20. Feb 2004 (CET)
Also Kernighan ist zwar Mitautor des Standardwerks mit D.M. Ritchie, gilt aber meines Wissens nicht als Mitschöpfer, sondern nur Richtie/Thompson Hubi 08:17, 25. Feb 2004 (CET)
Zu Portabilität. Liest man die frühen Dokumente von Ritchie/Thompson, kommt man drauf, dass die vielbeschworene Portabilität (ja C ist nun mal portabel) erst auf's Tapet kam, als sie von der alten PDP auf die neuere VAX portieren mussten. Grundgedanke von C (und Unix) ist m.E. viel mehr, generelle, jedoch überall anwendbare Konzepte zu erfinden. Portabilität ergibt sich dann im Nachhinnein. Ich erinnere mich mit einiger Wahrscheinlichkeit (weiss aber momentan die Quelle nicht so genau), dass Ritchie einmal schrieb portability was an afterthought, nämlich als sie finanzielle Mittel für die VAX beantragten. Das Design von C zeigt hier die Weitsicht ihrer Schöpfer Hubi 08:30, 25. Feb 2004 (CET)
Nochmal zu leistungsschwache Bibliotheken. Und was hatten denn die anderen Sprachen wie das z.B. die vom hochverehrten Niklaus Wirth entwickelte PASCAL? Nicht mal einen Linker. Also nicht nur leistungsschwache Bibliotheken, sondern gar keine! Bibliotheken gehören eher zum Betriebssystem/Entwicklungsumgebung als zur Sprache. Daher werd ich's entfernen. Und Wirth's gemeines und unpassendes Zitat auch (vgl. PASCAL). Hubi 08:39, 25. Feb 2004 (CET)
Portabilitätsprobleme? Der Verzicht auf genaue Längendefinition von short/int/long ermöglicht gerade die Portierung auf Itanium und auf PIC. C-Compiler gibt's für 8-Bit wie für 64-Bit und die halten sich an den Standard. Und ein frühes Unix-Programm namens lint entdeckt nicht portable Konstrukte. Mehr kann man kaum tun. Der Verzicht ist also eine Stärke von C. Sonst hätten wir PDP-gemäß vielliecht 18-Bit integer und 36-Bit long. Lange Zeit glaubten viele Programmierer, dass int, long und pointer alle 32-Bit lang wären (wie auf VAX, 68000, mit Einschränkung i386, ...) und murksten durch beliebige Typkonvertierung rum, ohne aufzupassen und sich an den Standard zu halten. Daher die Probleme mit 64 Bit-Portierungen. Hubi 08:49, 25. Feb 2004 (CET)
Mangelhafte Stringunterstützung? Wenn man die Sprachziele (einfache, generelle Konzepte) nimmt, ist mangelhaft wohl übertrieben. Und nimmt man wieder das etwa zur selben Zeit entstandene PASCAL, so sah's da noch düsterer aus (kennt jemand noch den Datentyp Alpha?). Und bei der Implementation von Betriebssystemen ist die Stringunterstützung genau richtig. Wer will da schon dynamische Allokierung haben. Niemand. Hubi 09:03, 25. Feb 2004 (CET)
Objektorientierung? Simula-67 hat dies zwar, aber das kam doch erst später. Daher kann man dies kaum der Sprache als Schwäche anlasten. Als ob die Sprache von Ignoranten, die nicht auf der Höhe der Zeit waren, entwickelt worden wäre. Werd ich einfach entfernen. Hubi 09:13, 25. Feb 2004 (CET)
Der Programmierer muss den dynamischen Speicher selbst verwalten. Hierzu stehen in der Regel Bibliotheksfunktionen zur Verfügung. Zunächst muss die erforderliche Größe an die Allokierungsfunktion übergeben werden. Die Routine gibt die Adresse zurück, die anschliessende Umwandlung in den entsprechenden Datentyp muss explizit durchgeführt werden. Die notwendige doppelte Angabe des Datentyps ist fehleranfällig. Auch die Freigabe von nicht mehr benötigtem Speicher muss über eine Bibliotheksfunktion durchgeführt werden. Sie wird oft vergessen, unbelegter Speicherplatz wird dann nicht freigegeben
Was soll der Absatz eigendlich? Dynamische Elemente muss man in fast allen Sprachen selbst anlegen, der Unterschied zwischen malloc/free und new/dispose liegt imho nur darin das ich die Größe des Speichers den ich brauche in C mit angeben muss. Freigeben muss ich den Speicher in vielen anderen Sprachen ebenfalls von Hand, ausser man hat einen garbage collector. Was die Typumwandlung angeht, ich hab zwar schon ewig keinen k&r compiler mehr benutzt aber das der überhaupt eine warnung bei "struct whatever_t *s = malloc(sizeof(struct whatever_t));" statt "struct whatever_t *s = (struct whatever_t *)malloc(sizeof(struct whatever_t));" ausgeben würde, das wage ich zu bezweifeln. Das man den Typ ein paar mal schreiben muss, seh ich ein aber irres ge'cast'e gibt auch in moderneren Sprachen ;-) Im übrigen das hat wenig mit dem Thema "Speicherverwaltung" zu tun, darunter würde ich verstehen das man die komplette Verwaltung des Heap von Hand machen müsste.195.243.149.235 20:53, 25. Feb 2004 (CET)
- Na ja, aber da gibt's immer wieder Probleme. Der ursprüngliche Artikel hatte einen Abschnitt Speicherverwaltung, der noch schlechter war. Das mit dem cast/sizeof kann man in C ja elegant durch ein Makro lösen :-). Allerdings sehe ich schon ein Problem (doppeltes free, falsche Pointerübergabe). Also kommt das wieder raus, ok? Hubi 07:27, 26. Feb 2004 (CET)
- Ich hab mal den ersten Satz dringelassen. Die Speicherverwaltung ist meines Erachtens ein Manko. Bei Bedarf ändern oder ganz weg. Hubi 07:38, 26. Feb 2004 (CET)