2012-04-06 9 views
9

Ich bin ein Anfänger in C, und ich spiele mit C. mir einen C-Code wie folgt eingegeben:Warum kompiliert dieses C-Programm ohne einen Fehler?

#include <stdio.h> 
int main() 
{ 
    printf("hello world\n"); 
    \ 
    return 0; 
} 

Auch wenn ich \ wissentlich verwendet, die C-Compiler keine Fehler werfen. Wofür wird dieses Symbol in der Sprache C verwendet?

Edit:

Auch dies funktioniert:

"\n"; 
+0

"\ n"; es ist eine Aussage ohne Wirkung. Es wird vom Compiler komplett ignoriert und generiert eine Warnung. Versuchen Sie, mit dem gcc -Wall-Flag zu kompilieren, das Kompilierungswarnungen aktiviert. – dAm2K

+3

Ihre Hauptfrage wurde mehrmals beantwortet. In Bezug auf den Teil über '" \ n ";' ist ein c-Programm (mehr oder weniger) eine Liste von Anweisungen. Ein Literalwert (wie '3' oder' "\ n" 'oder' 'hamburger'') ist eine absolut gültige Aussage, auch wenn es nichts tut. – jpm

Antwort

0

Der Backslash \ durch den C-Präprozessor interpretiert bekommen. Es schützt sein folgendes Zeichen (das neue Zeilenzeichen in Ihrem Fall).

+1

Eigentlich ist es das Gegenteil von "schützen"; Es stellt sicher, dass sowohl der Backslash als auch der Newline gelöscht werden. –

0

Der Backslash entkommt einfach dem nächsten Zeichen. In diesem Fall wahrscheinlich ein Zeilenendezeichen (CR). Perfekt vernünftig.

+0

Escapes in C sind nur in Strings aktiviert. –

+0

In der Tat konnte der Präprozessor nur das Zeilenende-Zeichen entkommen. Entschuldigung für die Irreführung. Die obige Antwort von dAm2k ist genauer. – rainecc

+0

@MatteoItalia: Phase 2 der Übersetzung lautet: "Jede Instanz eines Backslash-Zeichens (\\), unmittelbar gefolgt von einem neuen Zeilenzeichen, wird gelöscht, wobei physische Quellzeilen zu logischen Quellzeilen verbunden werden." (§5.1.1.2/1.1). –

11

Die Sequenz Backslash-Newline wird in einer sehr frühen Phase (Phase 2) des Übersetzungsprozesses aus dem Code entfernt. Früher haben Sie lange String-Literale erstellt, bevor eine String-Verkettung stattfand, und Sie erweitern Makros immer noch über mehrere Zeilen.

Siehe §5.1.1.2 Translation Phasen des C99-Standard:

Der Vorrang unter den Syntaxregeln der Übersetzung durch die folgenden Phasen angegeben wird. 5)

  1. Physikalische Quelldatei Mehrbyte-Zeichen abgebildet sind, in einer Implementierung definiert Weise mit dem Source-Zeichensatz (new-line Zeichen für end-of-line-Indikatoren) erforderlichenfalls einzuführen. Trigraph-Sequenzen werden durch entsprechende interne Ein-Zeichen-Repräsentationen ersetzt.
  2. Jede Instanz eines Backslash-Zeichens (\), unmittelbar gefolgt von einem neuen Zeichen , wird gelöscht, wobei physische Quellzeilen zu logischen Quellzeilen verbunden werden. Nur der letzte Backslash auf einer physischen Quellleitung darf als Teil eines solchen Spleißes verwendet werden. Eine Quelldatei, die nicht leer ist, muss in einem neuen Zeilenzeichen enden, , dem nicht unbedingt ein Backslash-Zeichen vorangestellt werden muss, bevor ein solches -Spleißen stattfindet.
  3. Die Quelldatei wird in Vorverarbeitungstoken zerlegt 6) und Sequenzen von Leerzeichen (einschließlich Kommentare). Eine Quelldatei darf nicht in einem teilweisen Vorverarbeitungstoken oder in einem Teilkommentar enden. Jeder Kommentar wird durch ein Leerzeichen ersetzt. Zeichen für neue Zeilen bleiben erhalten. Ob jede nicht leere Folge von Leerzeichenklassen außer Newline beibehalten oder durch ersetzt wird, ist ein Leerzeichen definiert.
  4. Vorverarbeitungsdirektiven werden ausgeführt, Makroaufrufe werden erweitert und _Pragma unäre Operatorausdrücke werden ausgeführt. Wenn eine Zeichenfolge, die die Syntax eines universellen Charakternamens entspricht, von Token Verkettung (6.10.3.3) erzeugt wird, ist das Verhalten nicht definiert.Eine #include Vorverarbeitung Direktive bewirkt, dass der benannte Header oder die Quelldatei rekursiv von Phase 1 bis Phase 4 verarbeitet wird. Alle Vorverarbeitungsdirektiven werden dann gelöscht.
  5. Jeder Quellzeichensatzmember und die Escape-Sequenz in Zeichenkonstanten und String-Literalen wird in das entsprechende Element des Ausführungszeichens konvertiert set; Wenn es kein entsprechendes Mitglied gibt, wird es in eine Implementierung konvertiert, die als Element definiert ist, das nicht das Nullzeichen (Wide) ist. 7)
  6. Benachbarte String-Literaltoken werden verkettet.
  7. Leerzeichen, die Token trennen, sind nicht länger von Bedeutung. Jedes Vorverarbeitungstoken wird in ein Token konvertiert. Die resultierenden Token werden syntaktisch und semantisch analysiert und als Übersetzungseinheit übersetzt.
  8. Alle externen Objekt- und Funktionsreferenzen sind aufgelöst. Bibliothekskomponenten sind verknüpft, um externe Referenzen auf Funktionen und Objekte zu erfüllen, die nicht in der aktuellen -Übersetzung definiert sind. Alle derartigen Übersetzerausgaben werden in einem Programmbild gesammelt, das Informationen enthält, die zur Ausführung in seiner Ausführungsumgebung benötigt werden.

5) Implementationen werden als verhalten, wenn diese getrennten Phasen auftreten, obwohl der Regel zusammengefaltet in der Praxis viele sind.

6) Wie in 6.4 beschrieben, ist der Prozess zum Teilen der Zeichen einer Quelldatei in Vorverarbeitungstoken kontextabhängig. Siehe zum Beispiel die Behandlung von < innerhalb einer #include Vorverarbeitungsrichtlinie.

7) Eine Implementierung muss nicht alle nicht entsprechenden Quellzeichen in die gleiche Ausführung Zeichen konvertieren.

Wenn Sie nach Ihrem streunenden Backslash ein Leerzeichen oder ein anderes Zeichen hatten, hätten Sie einen Kompilierungsfehler. Wir können feststellen, dass Sie nichts danach haben, weil Sie keinen Kompilierungsfehler haben.


Der andere Teil Ihrer Frage, etwa:

"\n"; 

ist ganz anders. Es ist ein einfacher Ausdruck, der keine Nebenwirkungen hat und daher keine Auswirkungen auf das Programm hat. Der Optimierer wird es komplett verwerfen. Wenn Sie schreiben:

i = 1; 

Sie haben einen Ausdruck mit einem Wert, der verworfen wird; es wird für seinen Nebeneffekt des Modifizierens i ausgewertet.

Manchmal werden Sie Code finden wie:

*ptr++; 

Der Compiler wird Sie warnen, dass das Ergebnis des Ausdrucks verworfen wird; der Ausdruck kann vereinfacht werden zu:

ptr++; 

und wird den gleichen Effekt im Programm erreichen.

+0

In der ersten Phase sind die "Zeilenenden-Indikatoren" implementiert. Nachrückender Leerraum könnte als Teil des Zeilenendenindikators betrachtet werden, sodass in Phase 2 dem umgekehrten Schrägstrich sofort eine neue Zeile folgen würde, obwohl in der ursprünglichen Eingabe Leerraum vorhanden war. –

+0

@JerryCoffin: In der Theorie sind Sie richtig. In der Praxis gilt meine vereinfachte Aussage für alle modernen Umgebungen, von denen ich je gehört habe. Haben Sie ein explizites Gegenbeispiel, bei dem der C-Compiler vor dem Backslash-Newline-Spleißen nachgestellte Leerzeichen entfernt? (Die genauen Regeln aus dem C99-Standard werden zitiert; jeder Kommentar, den ich mache, steht hinter dem Standard und die Bugs in der Implementierung werden verwendet.) –

+0

Nein, kein aktueller, obwohl ich mich an einen alten erinnern kann, der das getan hat Teil der Zeit. –

0

Der Backslash plus, was folgt ist ein escape sequence; "\ n" zusammen ist das Newline-Zeichen (druckt eine neue Zeile). Ein weiterer wichtiger ist "\ t", für Tab.

+0

Escape-Sequenzen treten nur in String- und Zeichenliteralen auf. Der umgekehrte Schrägstrich in der Frage befindet sich nicht in einer Zeichenfolge oder einem Zeichenliteral. –

4

Die \, wenn unmittelbar gefolgt von einer neuen Zeile, wird von der Vorverarbeitung verbraucht und bewirkt, dass die nächste "physische" Zeile mit der aktuellen logischen Zeile verbunden wird. Dies ist sehr wichtig für das Schreiben langen Vorverarbeitung Richtlinien, die alle auf einer logischen Zeile sein müssen:

#define SHORT very log macro \ 
    consisting of lots and \ 
    lots of preprocessor \ 
    tokens 

Wenn Sie die Backslash-Newline-Sequenzen entfernen, ist es nicht mehr richtig. Einige andere Sprachen aus der Unix-Kultur haben eine ähnliche Backslash-Zeilenfortsetzungssyntax: die aus der Bourne-Shell abgeleitete POSIX-Shell-Sprache und auch Makefiles.

$ this is \ 
one shell command 

Über "\n";, dass ein primärer Ausdruck verwendet, um einen Ausdruck-Äußerung zu bilden. In C können Ausdrücke als Anweisungen verwendet werden, und dies wird die ganze Zeit ausgenutzt. Ihr Aufruf printf zum Beispiel ist eine Ausdrucksanweisung. printf("hello world\n") ist ein Postfix-Ausdruck, der eine Funktion aufruft und einen Rückgabewert erhält. Da Sie diesen Ausdruck als Anweisung verwendet haben, wird der Rückgabewert verworfen. Der Rückgabewert von printf gibt an, wie viele Zeichen gedruckt wurden, oder ob es überhaupt erfolgreich war, also macht sich Ihr Programm durch Wegwerfen davon nicht bewusst, ob der Anruf tatsächlich funktioniert hat.

Da der Wert einer Ausdruck-Anweisung verworfen wird, wenn eine solche Anweisung auch keine Nebenwirkungen hat, ist es eine nutzlose Aussage, die nichts tut (wie Ihre "\n"). Aber solche unnützen Ausdrücke sind nicht falsch. Wenn Sie der Compiler-Befehlszeile Warnoptionen hinzufügen, erhalten Sie möglicherweise eine Warnung wie "Anweisung ohne Auswirkung" oder Ähnliches.

Verwandte Themen