Startseite > Piraten, Sonstiges, Statische Tags, Technik, Unsinn > Genau deswegen hasse ich C/C++

Genau deswegen hasse ich C/C++

Hier mal ein schönes Beispiel, warum ich C und C++ hasse. Nehmen wir doch dieses schöne, einfache Programm:

#include <stdio.h>

int main() {
	int zahl = 23;
	if (zahl > 5) {
		printf("Das sollte reichen: " + zahl);
	} else {
		printf("Das reicht nicht: " + zahl);
	}
}

Was gibt dieses Programm aus, wenn man es startet?

(Runterscrollen für die Lösung)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

Die Antwort lautet:

s reicht nicht: 

Also der Text aus dem else-Zweig, der eigentlich nicht aufgerufen werden kann, und auch noch am Anfang abgeschnitten, und die Zahl fehlt. Was ist passiert? Nun, die Zeichenketten werden hintereinander im Speicher abgelegt. Es wird sehr wohl der erste Zweig ausgeführt – aber es wird die Speicheradresse der ersten Zeichenkette genommen, die Zahl dazuaddiert und die Zeichenkette an dieser neuen Adresse ausgegeben. Logisch, oder? Und das ist nunmal ein Teil der zweiten Zeichenkette.

Ist ja auch völlig klar, dass man bei einer direkt im Quellcode konstant angegebenen Zeichenkette, wo man nicht einmal weiß, wo die landen wird, mit der Speicheradresse herumrechnen will. Klar ist das hier ein Fehler des Programmierers und der Compiler macht sicherlich nur das, was im Standard vorgesehen ist. Aber der gcc (3.4.5 mingw-vista special r3) hält es selbst mit gesetztem -Wall -Wextra (also sehr hohem Warnlevel) nicht im Geringsten für nötig, wenigstens eine Compilerwarnung auszugeben. (Angemessen wäre meiner Meinung nach gerade in diesem Fall schlichtweg ein Fehler. Wer wirklich auf den Pointern herumrechnen will, kann ja casten.) Natürlich hat das alles seine Richtigkeit: Der Text hat den Typ char* (also ein Pointer), und dazu kann man wunderbar einen int addieren. Was sonst sollte man denn damit machen…

Ich sage übrigens nicht, dass automatisch mehr Speicher allokiert, die Zahl in einen Text umgewandelt, an den ursprünglichen String drangehängt und ausgegeben werden muss – eine schlichte Fehlermeldung, dass „Text“ und „Zahl“ sich nicht addieren lassen, wäre völlig ausreichend.

Dieses einfache Beispiel zeigt aber, wie maschinennah man bei C/C++ programmiert. (Update: Ein weiteres, mindestens genauso fieses Beispiel siehe hier.) Dadurch, dass man so direkt auf dem Speicher arbeitet, und sich um viele Kleinigkeiten manuell kümmern muss, entsteht viel Code, mit vielen Fehlern, und „Fehler“ heißen beim Umgang mit rohem Speicher und fremden Daten desöfteren „Sicherheitslücke wegen der man sich schon beim Anschauen einer Website nen Virus fängt“. Ergänzung – zum Beispiel so (Hervorhebung von mir):

Adobe hat seinen Shockwave Player auf Version 11.5.8.612 aktualisiert und schließt damit wieder einmal zahlreiche Sicherheitslücken, von denen Angreifer mindestens 18 zum Einschleusen von Schadcode missbrauchen können. Ursache für die meisten Schwachstellen sind Speicherfehler in diversen Funktionen […]

Die meisten Exploits der letzten Jahre dürften wir tatsächlich C/C++ verdanken.

Zudem habe ich noch den Eindruck, dass entweder durch den üblichen Programmierstil und/oder durch die vielen Kleinigkeiten, die man manuell machen muss, C/C++-Programme im Vergleich zu anderen Sprachen deutlich schlechter lesbar sind.

Für mein Tool DarkLock hatte ich das „Vergnügen“, die Windows-API aus C++ heraus aufrufen zu müssen. Insbesondere die Funktion PowerDuplicateScheme gefällt mir, weil sie stellvertretend für viele andere Funktionen zeigt, wie viel „Spaß“ C++ macht. Diese erhält als Parameter die Konstante NULL (ist halt so…), einen Pointer auf die GUID des einen Schemas, und einen Pointer auf einen Pointer auf eine GUID. Richtig gelesen. Macht auch absolut Sinn, denn wenn der Pointer auf einen Nullpointer pointet, wird eine neue GUID erzeugt und der Nullpointer durch den Pointer auf die GUID ersetzt. Alles klar? (Man muss danach nur noch den Speicher richtig freigeben…)

Den Rest von DarkLock hab ich dann in C# geschrieben, einer Sprache die mehr Java als C ähnelt und deutlich weniger Schmerzen hervorruft. (Und ja, ich weiß, dass es für C durchaus Libraries gibt, die obiges Problem lösen würden.)

Es gibt sicherlich Fälle, wo C und C++ noch Sinn machen (Embedded-Systeme, Dinge die mit hoher Leistung laufen müssen, Sachen die aus sonst einem Grund derart maschinennah sein sollen, …) – für die alltägliche Programmierung von Desktopanwendungen will ich den Kram aber nicht mehr sehen. Wem meine Kritik auf viel zu niedrigem Niveau ist, darf sich gern bei Fefe bedienen.

Gibt es eigentlich einen GUI-Editor für Java, der ähnlich gut ist wie der von Visual Studio? Ich habe nämlich keine Lust, 70% der Zeit damit zu verbringen GUIs zu schreiben. Auch nett wäre, wenn die „höheren“ Sprachen eine einfache Möglichkeit bieten würden, bei Bedarf doch mal auf ein niedrigeres Level zu wechseln (mit den damit verbundenen Nachteilen), oder zumindest (gerade Java) irgendwas, um bequem mit „rohen“ Bytes (gerne durchaus in verwaltetem, geschützem Speicher!) sinnvoll arbeiten und rechnen zu können.

  1. 2010-08-21 um 16:27 UTC

    Beim C-Programmieren sollte man C programmieren und kein JavaScript.

    • Jan
      2010-08-21 um 19:28 UTC

      Und damit willst du was sagen?

      • a nonym
        2010-11-09 um 13:52 UTC

        #include
        int main() {
        int zahl = 23;
        if (zahl > 5) {
        printf(„Das sollte reichen: %d\n“, zahl);
        } else {
        printf(„Das reicht nicht: %d\n“, zahl);
        }
        }

        • Anonymous
          2012-05-12 um 19:09 UTC

          Wobei man sich trotzdem mal vertippen kann. Und dann sucht man evtl. erstmal etwas…

  2. Anonymous
    2010-08-22 um 07:35 UTC

    NetBeans hat einen gute GUI-Editor für Java

    • Jan
      2010-08-22 um 20:25 UTC

      Danke. Für Swing ist das echt gut, und Swing scheint mir auch deutlich brauchbarer (nativ aussehender) geworden zu sein. Cool!

  3. nils
    2010-08-22 um 10:18 UTC

    Schöner Bug. Sehr gut versteckt. Aber wie alles eine Frage der Gewöhnung.

    Ich bin vor zwei Monaten nach 20 Jahren C und C++ für ein kleines Projekt schnell mal auf Java rübergewechselt. Ist ja auch eine der C ähnlichen Sprachen, und der Wechsel ging richtig schnell. Nach nur zwei Wochen fühlte ich mich zuhause in der Sprache..

    Zwischendurch hätte ich *genau* so ein Schrei-Post wie Du über die Tatsache schreiben können, das der == Operator etwas anderes macht wie blubb.equals().

    Btw – ich geb Dir absolut recht, das C++ auf dem Desktop für performance unkritische Applikationen nichts mehr zu suchen. Da will ich auch nur noch VM basierte Sprachen sehen. Die Kisten, an den wir heute sitzen sind wirklich schnell genug. Wenn man doch mal bessere Performance hier und da braucht (multi-media codecs, crypto-algorithmen usw). Dann soll man halt die native Interfaces benutzen.

    Funktioniert bei Java und C# ganz wunderbar.

    Bei Java ist das Native Interface JNI sogar über mehrere Betriebssysteme und CPU-Architekturen portabel. Man muss nur die native library neu übersetzten und gut ist.. Hätte ich nicht gedacht.

  4. 2010-08-23 um 15:56 UTC

    Und was hat das mit den Piraten zu tun?

    • Jan
      2010-08-24 um 01:39 UTC

      Nichts. Die Kategorie „Piraten“ ist eine rein technische Kategorie für den Piratenplanet/Piratenmond. Das habe ich so eingerichtet, um einzelne Beiträge in Ausnahmefällen rausnehmen zu können, z. B. sowas. Da aber normalerweise ganze Blogs in den Planet aufgenommen werden, und es „Piraten bloggen“ heißt und nicht „Piraten bloggen über Piraten/Politik“, stopfe ich alle Beiträge bis auf Ausnahmen die ich explizit nicht reinnehmen will da rein. Falls das nicht gewünscht ist, kann ich das natürlich ändern.

  5. sdfdf
    2010-08-24 um 08:46 UTC

    Du beherrscht also die Sprache nicht und das ist die Schuld der Sprache *facepalm*.

    „Angemessen wäre meiner Meinung nach gerade in diesem Fall schlichtweg ein Fehler“

    *erneutes facepalm*. Ein Beitrag, den die Welt nicht gebraucht hat.

    • Jan
      2010-08-25 um 02:34 UTC

      Richtig ;-)

      Das Problem an C/C++ ist, dass die Sprache zahlreiche Stolperfallen enthält, die sie schwer/kaum beherrschbar machen. Das führt dann dazu, dass durchaus deutlich fähigere Leute als ich früher oder später einen kleinen unscheinbaren Fehler machen, der sich dann ein paar Jahre später in Form eines neuen Exploits auf Heise wiederfindet.

  6. Christian
    2010-08-28 um 08:30 UTC

    Klar, C ist „high level assembler“. Da gehört es einfach dazu, dass ein Zeiger standardmäßig wie ein numerischer Wert behandelt wird.

    Was die vermisste Warnung anbelangt, Jan, hast du mit „gcc (3.4.5 mingw-vista special r3)“ vermutlich eine zu alte Version erwischt. Bei meinem Test wurden entsprechende Warnungen ausgegeben:


    $ cat --number print.c
    1 #include
    2
    3 int main() {
    4 int zahl = 23;
    5 if (zahl > 5) {
    6 printf("Das sollte reichen: " + zahl);
    7 } else {
    8 printf("Das reicht nicht: " + zahl);
    9 }
    10 }
    $ gcc --version
    gcc (Gentoo 4.4.4-r1 p1.0, pie-0.4.5) 4.4.4
    Copyright (C) 2010 Free Software Foundation, Inc.
    Dies ist freie Software; die Kopierbedingungen stehen in den Quellen. Es
    gibt KEINE Garantie; auch nicht für MARKTGÄNGIGKEIT oder FÜR SPEZIELLE ZWECKE.

    $ gcc --ansi print.c -o print
    print.c: In Funktion »main«:
    print.c:6: Warnung: Format ist kein Zeichenkettenliteral, und keine Formatargumente
    print.c:8: Warnung: Format ist kein Zeichenkettenliteral, und keine Formatargumente
    $

    Was das Verwenden eines GUI-Editors angeht: Ja, solche GUI-Editoren können hilfreich sein und gerade für kleine Anwendungen will man sich das nicht von Hand zusammenschreiben. Doch bei größeren/komplexeren Anwendungen, bei denen zur Compilezeit noch gar nicht bekannt ist wie die GUI aussehen soll, kommt man da nicht herum. Man muss den Code zur Erstellung und zur Platzierung dann selbst schreiben, das geht mit Java auch ganz gut, finde ich.

    • Christian
      2010-08-28 um 08:33 UTC

      Nachtrag: Mit „–Werror“ wäre der Fehler definitiv aufgefallen, da der Compilevorgang abgebrochen worden wären.

    • Jan
      2010-08-29 um 06:36 UTC

      „high level assembler“ find ich gut – das trifft den Nagel wirklich auf den Kopf.

      Die Warnung deines Compilers bezieht sich leider ausdrücklich auf printf (und dadurch mögliche Format Strings Attacks), ich befürchte, dass für jede andere Strings benutzende Funktion immer noch keine Warnung käme.

  7. sky
    2010-11-12 um 07:32 UTC

    um alle hier genannten bedenken und einwände mit einem male zu erschlagen: delphi ist eine echte alternative ! wer jetzt fragt „und was ist daran besser?“, der soll es sich mal anschauen… die aktuellen versionen 2010/XE überzeugen echt !

    greez,
    sky…

  1. 2011-02-08 um 06:03 UTC

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: