Warum compiliert das nicht?

Ich bin auf ein merkwürdiges Phänomen in C gestoßen, vielleicht kann mir das jemand erklären. Extrem eingedampft sieht das Problem so aus:

int main(int argc, char* arg[]) {
    int i = 0;
    switch (i) {
        case 0:
            int j = 7;
            break;
    }
}

Der Compiler (aufgerufen mit ‚gcc test.c‘) sagt dazu „t.c:5: error: expected expression before ‚int‘„. Mit geschweiften Klammern funktioniert der case-Block dagegen prima:

case 0: {
    int j = 7;
    break;
}

Zu meinem grössten Erstaunen klappt auch folgender Block:

case 0:
    i = 3;
    int j = 7;
    break;

Es geht halt nur nicht wenn direkt nach dem case eine Variablendeklaration kommt.

Wenn man schon innerhalb eines case eine Variable deklarieren kann… warum dann nicht ganz am Anfang? Ich meine: ich habe ja Lösungen für das Problem. Mir fehlt halt nur das ‚Problembewusstsein‘. Kann mir das jemand vermitteln?

5 Kommentare

  1. > Zu meinem grössten Erstaunen klappt auch folgender Block:
    > […]

    Damit erstaunst du mich ebenfalls … bin nämlich nicht auf die Idee gekommen, sowas auszuprobieren.

    … nach einer Weile Nachdenken und in der C-Sprachbeschreibung blättern, denke ich, dass ich es erklären kann.
    Dort steht zu case:
    case :

    Nun ist ‚i = 3;‘ eine und ein Block ebenfalls.
    Aber ‚int j = 7;‘ ist aber keine , sondern (soweit ich das hier rauslese) ein .

    Wenn man nun das case nochmal hernimmt, dann ist die allgemein übliche Einrückung eigentlich nicht ganz richtig.
    Denn es müsste vielmehr so aussehen:

    switch (i) {
    case 0:
    int j = 7;
    i = 3;
    break;
    }

    Nur die erste Zeile nach dem case gehört zu ihm. Die anderen sind ganz normale Anweisungen.
    Denn denn case ist eigentlich nicht mehr als eine Sprungmarke … Es wird also nach ihr ganz normal im Code weitergearbeitet.

    … das hat Kernighan schon recht, wenn er schreibt, dass switch in C nicht gut entworfen wurde.

    Ich habe mir das gerade so zusammengereimt … und es sieht recht gut und logisch aus.
    Ob es das allerdings wirklich ist, kann ich nicht sagen. :-)

    meillo

  2. Mist, jetzt ist die Einrückung kaputt gegangen.
    Hier nochmal mit Ersatzzeichen.
    (… könntest du vielleicht irgendwo aufführen, was für BB-Code man verwenden kann.)

    switch (i) {
    ….case 0:
    ……..int j = 7;
    ….i = 3;
    ….break;
    }

    Das funktioniert also nicht, weil die eingerückte Zeile (‚int j = 7‘) keine ist. Bei ‚i = 3;‘ oder einem Block dagegen schon.

  3. Hmm, leider ist in Deiner ersten Antwort (danke dafuer) mehr kaputt gegangen als nur die Einrueckung. Zumindest wirft mein Hirn einen Parser-Fehler an der Stelle „ist aber keine , sondern (soweit ich das hier rauslese) ein .“ :-)

    Ich haette irgendwie gedacht dass sowohl „i = 3;“ als auch „int i = 3;“ eine Zeile ist.

    An anderer Stelle hat mir uebrigens jemand gesagt dass durch das ‚case 0:‘ kein neuer Block anfaengt, sondern dass das quasi mitten im Code ist. Weil das eben nur eine Sprungmarke ist. Klar kann man mitten im Code in C keine Variablen deklarieren, also habe ich es mit „-std=c99“ versucht. Klappt aber auch nicht, der Effekt ist der gleiche.

    Aber mit dem BB-Code hast Du recht, das muesste ich eigentlich mal selbst in Erfahrung bringen.

  4. Ja, jetzt sehe ich es auch: Ich hatte dort „expression“ und „statement“ und so in spitzen Klammern gesetzt um sie hervorzuheben … naja, das wir alles als „böses HTML“ eliminiert worden. :-S (Wie ich das hasse!)

    ‚int j = 7;‘ ist keine expression, aber eine solche muss auf eine case-Marke folgen.
    ‚i = 3;‘ genauso wie ein Block ({}) sind aber expressions und statements und deshalb erlaubt.

    Es ist korrekt, dass nach case kein Block beginnt. es ist einfach eine Marke im Code, der ein statement folgen muss. (Ich sehe gerade, dass jeder Sprungmarke, also auch die für goto, ein statement folgen muss.)
    Die Einrückungen im zweiten Post, sollen nur zeigen, dass die erste Anweisung nach dem case, zum diesem gehört und die anderen ganz normaler Code sind. Besser wäre es allerdings so:

    switch (i) {
    ….case 0: int j = 7;
    ….i = 3;
    ….break;
    }

    > Ich haette irgendwie gedacht dass sowohl “i = 3;” als auch “int i = 3;” eine Zeile ist.
    „Zeile“ ist ein bedeutungsloser Begriff in C.
    Hast du den ein „the c programming language“ (oder auf Deutsch „Programmieren in C“) von K&R zur Hand (btw: sollte jeder haben)? Da steht es im Anhang A ganz ausführlich. (Wenn auch nicht ganz einfach verständlich.)
    Ansonsten gibt es die Sprachbeschreibung zu C, also den C-ANSI-Standard sicher auch im Netz.

    Der Unterschied ist halt, dass ‚i=3;‘ ein statement ist, und ‚int j;‘ (genauso wie ‚int j = 7;‘) eine deklarator (und kein statement). Nach einer Marke wird aber ein statement verlangt.

    Klar, dass du das nicht nachvollziehen konntest, wenn die entscheidenden Begriffe im ersten Post eliminiert wurden. ;-)

    (btw: hab meine Emailadresse eingefügt, darfst mich gerne anschreiben.)

  5. @meillo: Danke, das macht einiges klarer. Warum C das so macht kann ich allerdings immer noch nicht nachvollziehen. Ich denke ich werde das einfach mal so hinnehmen muessen…

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.

;-) :-) :-D :-| :-/ :-( :-P more »