2016-07-16 12 views
1

Betrachten Sie einen Ausdruck *(1+"AB" "CD"+1)Schalterkasten Ausdruck

Was ist die Lösung für diesen Ausdruck? Der obige Ausdruck ist ein Schalterausdruck in C.

*(2+"AB" "CD") --> *(2+"ABCD") --> ? 

Danach was soll ich tun? Unten ist der Code-Schnipsel:

#include<stdio.h> 
void main(){ 
    switch(*(1+"AB" "CD"+1)){ 
     case 'A':printf("Pulp Fiction"); 
        break; 
     case 'B':printf("12 Angry Man"); 
        break; 
     case 'C':printf("Casabance"); 
        break; 
     case 'D':printf("Blood Diamond"); 
    } 

} 
+0

haben Sie versucht, es auszuführen? Was war die Ausgabe? – SMA

+0

Warum schreiben Sie unlesbaren Code? –

+0

Wenn dies Hausaufgaben sind, verwenden Sie die gewählte Sprache mit Ihrem Professor über den Mangel an Stil: falscher Prototyp für 'main()' und fehleranfälliges, fehlendes 'break;' am Ende des Schalterblocks. – chqrlie

Antwort

3

Code Laufen Sie Antwort "Casabance"

  • "AB" "CD" gleich "ABCD"
  • *("ABCD") Punkte 'A'
  • *("ABCD" + 0) Punkte zu 'A' bekommen
  • *("ABCD" + 1) verweist auf 'B'
  • *("ABCD" + 2) Punkte 'C'
  • 'C' Antwort "Casabance"
6

Casabance.

Wenn Sie

char *cp; 
int i; 

dann cp[i] == *(cp+i) == *(i+cp) == i[cp] haben.

C11 6.5.2.1:

A Postfix Ausdruck durch einen Ausdruck in eckigen Klammern [] ist eine indizierte Bezeichnung eines Elements eines Arrays Objekts. Die Definition des tiefgestellten Operators [] ist, dass E1 [E2] identisch mit (* ((E1) + (E2))) ist.

und C11 6.5.6:

Wenn ein Ausdruck, der Integer-Typ hat hinzugefügt oder von einem Zeiger subtrahiert, hat das Ergebnis die Art des Zeigers Operanden. Wenn der Zeigeroperator auf ein Element eines Array-Objekts zeigt und das Array groß genug ist, zeigt das Ergebnis auf einen Elementoffset aus dem ursprünglichen Element , so dass die Differenz der Indizes der resultierenden und ursprünglichen Arrayelemente gleich ist der ganzzahlige Ausdruck.

Ein String-Literal ist nur ein Char-Zeiger, soweit der Compiler betroffen ist.

Zwei Stringliterale nebeneinander auto Verketten zu einer einzigen Stringliteral:

C11 6.4.5:

In Übersetzungs Phase 6 werden die Mehrbyte-Zeichensequenzen durch beliebige Sequenz benachbarter Zeichen spezifiziert und identisch Präfix-String literalen Token in einen einzelnen Multibyte-Zeichen verkettete Sequenz.

So ... *(1+"AB" "CD"+1) == *(1+"ABCD"+1) == *("ABCD"+1+1)==*("BCD"+1) == "BCD"[1] == 'C'.

+0

Deine letzte Zeile hat einige Fehler, es gibt ein '+' zu viel für den ersten Ausdruck, und gegen Ende muss es '2' anstelle von' 1' geben. –

+0

Ich habe die String-Katze repariert, danke. Die am Ende waren absichtlich. Die Addition ist links nach rechts, also "ABCD" + 1 + 1 == "BCD" + 1 "nicht" "ABCD" + 2 ". Ich hätte wirklich "1+" ABCD "+1 ==" BCD "+ 1" als einen Schritt setzen sollen, aber nicht aus Gründen der Klarheit entschieden. – evaitl

+0

Ah, richtig, ich habe diese Subtilität nicht gesehen. –

1

Hier ist eine Beschreibung der verschiedenen Schritte, die alle bei der Kompilierung durchgeführt:

  • Die Reihenfolge der Stringliterale "AB" "CD" bei der Kompilierung in einem einzigen Stringliteral "ABCD" verkettet wird.
  • Diese Stringliteral Kompilierungen in ein Array von 5 char, mit den Werten initialisiert 'A', 'B', 'C', 'D' und '\0'.
  • In dem Ausdruck 1 + "ABCD" + 1 verfällt das Array in einen Zeiger auf sein erstes Element, der Zeiger wird um 2 inkrementiert, um auf das dritte Element zu zeigen, in diesem Fall das C Byte.
  • Die Dereferenzierung dieses Zeigers ergibt den char Wert 'C'.
  • Der Schalterausdruck hat einen konstanten Wert 'C', konvertiert in einen int, obwohl es kein konstanter Ausdruck ist, wie durch den C-Standard definiert.
  • Der Compiler wird die switch in einen einzigen Aufruf printf mit der Zeichenfolge "Casabance", wahrscheinlich optimieren kann auf http://gcc.godbolt.org/#

Hinweis überprüft werden, dass der Prototyp für main in falsch in Ihrem Beispiel, es int main(void) sein sollte oder int main(int argc, char *argv[]) oder gleichwertig. Darüber hinaus ist es fehleranfällig, die break; am Ende der letzten case oder default Klausel im switch Block wegzulassen.

+0

* Der Ausdruck des Schalters ist daher konstant * Der Ausdruck im Schalter ist nicht konstant. – 2501

+0

@ 2501: Der Ausdruck im Schalter muss nicht konstant sein. Es kann in diesem Fall als solcher vom Compiler behandelt werden. – Olaf

+0

@ 2501: Guter Punkt, ich werde meine Erklärung umformulieren, der Ausdruck hat einen konstanten Wert, obwohl es kein * konstanter Ausdruck * ist, wie vom C-Standard definiert. – chqrlie