Leonidas hat geschrieben:
Ebenso ist das anmängeln der Syntax total daneben, das ist nicht lustig das ist blöd. Man kann durchaus eine angenehme Sprache mit Curly Braces machen. Schaut euch mal blackbird an, der findet seit letztens auch JavaScript toll.
Es geht doch nicht um ``{}``-Syntax im Zusammenhang mit Inkonsistenz. Darum ging es auch nicht dem Autor das ``{}`` benutzt wird. Nein, es geht darum, wie Jack schon sagt, um wirklich strange inkonsistente Sachen.
Hier mal ein Beispiel:
Code: Alles auswählen
int a=1, b=2;
if (a=b) {
printf("a ist gleich b\n");
};
Wenn man das Programm startet, erscheint die Ausgabe "a ist gleich b", obwohl a und b ganz offensichtlich verschieden sind. Der versierte C-Nutzer sieht bei diesem einfachen Beispiel natürlich sofort den Fehler - gemeint war wohl (a==b) - nur warum merkt der Übersetzer das nicht?
Ja, weil erstens a=b zwar hauptsächlich eine Anweisung ist, welche den Wert von b in a hineinkopiert, zusätzlich ist aber a=b auch noch ein Ausdruck, welcher b als Wert zurückliefert . Für die if-Anweisung hätte es also den gleichen Effekt, als würde man gleich if(b) schreiben. Und das wird zweitens dummerweise auch noch akzeptiert, weil if nicht zwischen Wahrheitswerten und Ganzzahlen unterscheidet.
Das ist ja noch harmlos.
Code: Alles auswählen
int a=10, b=8, c=6;
if (a<=b<=c) {
printf("%d <= %d <= %d\n", a, b, c);
}
Man staunt und wundert sich, ob der Rechner jetzt wohl die Relationszeichen vertauscht hat, weil dieses Programm tatsächlich behauptet, dass 10 ≤ 8 ≤ 6. Der Grund ist einmal mehr im versuppten Typenkonzept von C zu finden. Der Übersetzer geht so vor: Der Ausdruck wird von links nach rechts ausgewertet, das entspricht der Klammerung ((10≤8)≤6). Jetzt wird der erste Vergleich ausgewertet: 10≤8 ist falsch, für C entspricht das einer 0. Nun wird diese 0 in den zweiten Vergleich gesteckt: 0≤6 ist wahr, also für C gleich 1, also für if wiederum wahr. Dumm gelaufen, was?
Dass wir uns nicht falsch verstehen: Der Übersetzer braucht diese verketteten Vergleiche nicht zu unterstützen. Sie sind Schreibvereinfachungen, die sich aber nicht damit vertragen, dass Vergleiche eigentlich Relationen zwischen zwei und zwar genau zwei Werten sind. Aber man kann von dem Übersetzer erwarten, dass er solche Irrtümer bemerkt, weil es eigentlich keine sinnvolle Interpretation für den Ausdruck "10 ≤ 8 ≤ 6" gibt, wenn man "≤" als Operation mit zwei Argumenten (linke Seite und rechte Seite) auffasst. Diese Sichtweise ist auch sinnvoll, denn alles andere wäre kaum wasserdicht zu definieren.
Hey, aber auch das ist ja noch nicht sooo schlimm.
Preisfrage: Was steht hier?
pi * diameter;
Blöde Frage, das ist natürlich die bekannte Formel zur Berechnung des Kreisumfanges aus dem Kreisdurchmesser. Lediglich das Speichern des Ergebnisses wurde vergessen.
Schaut noch einmal genau hin. Ganz genau. Würdet ihr eure Antwort ändern, wenn ich noch 100 Euro drauf lege? Ach nein, das ist die falsche Sendung.
Ich habe noch nicht verraten, dass pi ein Typbezeichner ist. Er steht für "product information" oder so und wird weiter oben im Programm definiert. Demnach wird hier die Zeigervariable diameter eingeführt, welche auf Objekte vom Typ pi zeigt.
Wir sehen, dass in C die Syntax für Deklarationen und arithmetische Ausdrücke nicht unterschieden werden kann, dass man also zum Erkennen der Programmstruktur bereits Informationen über die Bedeutung der Bezeichner benötigt. Bei C++ wird übrigens alles noch viel besser.
Nachdem wir nun schon so viel Spaß mit dem Anlegen von Feldern hatten, wie ist es dann mit der Benutzung derselben? Wenn a ein Feld ist, dann bezeichnet a dessen i. Eintrag. Lustigerweise bezeichnet i[a] aber dasselbe! Der Grund ist, dass a syntaktischer Zucker für *(a+i), wobei a+i Zeigerarithmetik ist. Bei der Addition eines Zeigers a und einer ganzen Zahl i (Reihenfolge egal) hat das Ergebnis den Typ des Zeigers. Allerdings wird nicht einfach der Wert von i zu dem Zahlenwert des Zeigers a addiert, sondern es wird das Produkt von i und der Größe des Datums, auf das a zeigt, zu a addiert. Diese Erkenntnisse sind essentiell, um bei Wettbewerben um möglichst unverständlichen C-Code gut abschneiden zu können.
Da muss noch mehr herauszuholen sein! Wie wär's denn mit zweidimensionalen Feldern? Normalerweise indiziert man ein zweidimensionales Feld a so: a[j]. Aber mit unserem Wissen können wir das gleiche viel schöner schreiben, etwa:
* i[a][j]
* j[i[a]]
* j[a]
* (a+i)[0][j]
* ((a+i)[0]+j)[0]
* j[*(a+i)]
* (*(a+i))[j]
* *((a+i)[0]+j)
Das ist ein absolut unverzichtbares Werkzeug um den Lesern seiner Programme überdurchschnittliches Wissen über C zu demonstrieren. Entwickler aller Länder schätzen es, Programme von solch erfahrenen Programmierern weiterentwickeln zu dürfen.
Das ist einer meiner Lieblinge
*i*
Hey, ist aber alles nicht so schlimm. Man lernt es auswendig und macht dann diese Fehler die daraus resultieren könne nicht mehr. Auch Bufferoverflow oder Speicherlecks lassen sich als Profi vermeiden...
*/i*
BTW: Und das ist ja noch nicht 10% der Inkonsistenz die in C existiert. Was ich besonders schön an C finde ist die richtig starke Typsicherheit!
Nett ist auch folgendes: http://www.wackerart.de/c.html