Compiler-Warnung "Kein Zeilenumbruch am Dateiende"

187

Was ist der Grund für die folgende Warnung in einigen C ++ - Compilern?

Kein Zeilenumbruch am Dateiende

Warum sollte ich am Ende einer Quell- / Header-Datei eine leere Zeile haben?

Brian Tompsett - 汤 莱恩
quelle
17
Nicht wirklich der Grund, aber es ist sehr ärgerlich, wenn Sie cateine Datei haben und sie keine nachfolgende neue Zeile enthält, da die neue Shell-Eingabeaufforderung nach der letzten Zeile der Datei erscheint (dh nicht in Spalte 0)
ThiefMaster
@ThiefMaster Mein $ PS1 beginnt genau aus diesem Grund mit einer neuen Zeile. (Es ist sowieso eine mehrzeilige Eingabeaufforderung, die eine Reihe nützlicher Informationen in einer Zeile und dann nichts als ein Eingabeaufforderungszeichen in der nächsten enthält, damit ziemlich lange Befehle nicht umbrochen werden.)
bames53
7
Why should I have an empty line at the end of a source/header file- Wenn eine Textdatei enthält one\ntwo\nthree\n, enthält sie drei Zeilen, von denen keine leer ist. Wenn eine Textdatei enthält, handelt one\ntwo\nthreees sich nicht um eine Textdatei, im gleichen Sinne, dass ein Satz ohne Punkt am Ende kein Satz ist.
Brandin

Antworten:

217

Denken Sie an einige der Probleme, die auftreten können, wenn keine neue Zeile vorhanden ist. Gemäß dem ANSI-Standard #includefügt die Datei am Anfang die Datei genau so ein, wie sie sich an der Vorderseite der Datei befindet, und fügt die neue Zeile nicht #include <foo.h>nach dem Inhalt der Datei ein. Wenn Sie also eine Datei ohne Zeilenumbruch am Ende des Parsers einfügen, wird diese so angezeigt, als ob sich die letzte Zeile von foo.hin derselben Zeile wie die erste Zeile von befindet foo.cpp. Was wäre, wenn die letzte Zeile von foo.h ein Kommentar ohne neue Zeile wäre? Jetzt ist die erste Zeile von foo.cppauskommentiert. Dies sind nur einige Beispiele für die Arten von Problemen, die auftreten können.


Ich wollte nur Interessenten auf James 'Antwort unten hinweisen. Während die obige Antwort für C immer noch korrekt ist, wurde der neue C ++ - Standard (C ++ 11) geändert, sodass diese Warnung nicht mehr ausgegeben werden sollte, wenn C ++ und ein Compiler verwendet werden, der C ++ 11 entspricht.

Aus dem C ++ 11-Standard über James 'Post:

Eine Quelldatei, die nicht leer ist und nicht in einem neuen Zeilenzeichen endet oder die in einem neuen Zeilenzeichen endet, dem unmittelbar ein Backslash-Zeichen vorangestellt ist, bevor ein solches Spleißen stattfindet, wird so verarbeitet, als ob ein zusätzliches neues Zeichen. Zeilenzeichen wurden an die Datei angehängt (C ++ 11 §2.2 / 1).

TJ Seabrooks
quelle
28
In der Praxis fügt natürlich jeder Compiler nach dem #include eine neue Zeile hinzu. Gott sei Dank.
mxcl
3
Ich erinnere mich, dass eine alte Version von Microsoft Visual C ++ (wie 2.x oder so) genau dieses Problem hatte. Es wurde verschärft, weil der IDE-Editor diese Art von Verhalten bei fehlenden Zeilenumbrüchen unterstützte.
Greg Hewgill
2
Compiler beschweren sich derzeit möglicherweise nicht, GitHub jedoch tatsächlich.
Puyover
1
Ich kann die "unten" Antwort von James sehen, aber: "Die obige Antwort" in OrderBy what?! Oben ist die Frage, wie ich sie normalerweise nach Stimmen bestelle. Oder meinst du deine eigene Antwort?
mbx
@Thomas: Ruft dieses Programm undefiniertes Verhalten auf, weil es nicht mit einer neuen Zeile endet. Siehe Programm hier: ideone.com/jswwf9
Destructor
44

Die Anforderung, dass jede Quelldatei mit einem nicht maskierten Zeilenumbruch endet, wurde in C ++ 11 entfernt. Die Spezifikation lautet jetzt:

Eine Quelldatei, die nicht leer ist und nicht in einem neuen Zeilenzeichen endet oder die in einem neuen Zeilenzeichen endet, dem unmittelbar ein Backslash-Zeichen vorangestellt ist, bevor ein solches Spleißen stattfindet, wird so verarbeitet, als ob ein zusätzliches neues Zeichen. Zeilenzeichen wurden an die Datei angehängt (C ++ 11 §2.2 / 1).

Ein konformer Compiler sollte diese Warnung nicht mehr ausgeben (zumindest nicht beim Kompilieren im C ++ 11-Modus, wenn der Compiler über Modi für verschiedene Revisionen der Sprachspezifikation verfügt).

James McNellis
quelle
4
Das ist alles schön und gut für C ++; Leider sagt C immer noch, dass es UB ist, selbst im neuesten Entwurf des kommenden C1X-Standards.
Adam Rosenfield
11
Diese Frage ist mit [c ++] und nicht mit [c] gekennzeichnet.
James McNellis
3
Trotzdem ist es wahrscheinlich sollte [c] markiert werden, da viele Menschen für diese Warnung in C suchen ihren Weg finden Sie hier.
Adam Rosenfield
1
Dies ist immer noch ein guter Punkt, um hinzuzufügen. Addieren Sie dies oben. Hoffe es macht dir nichts aus.
TJ Seabrooks
25

C ++ 03 Standard [2.1.1.2] erklärt:

... Wenn eine Quelldatei, die nicht leer ist, nicht in einem Zeilenumbruchzeichen oder in einem Zeilenumbruchzeichen endet, dem unmittelbar ein Backslash-Zeichen vorangestellt ist, bevor ein solches Spleißen stattfindet, ist das Verhalten undefiniert.

Igor Semenov
quelle
16

Die Antwort für "gehorsam" lautet "weil der C ++ 03-Standard besagt, dass das Verhalten eines Programms, das nicht mit Zeilenumbruch endet, undefiniert ist" (umschrieben).

Die Antwort für Neugierige ist hier: http://gcc.gnu.org/ml/gcc/2001-07/msg01120.html .

Vytautas Shaltenis
quelle
4
Ahh, das geliebte "undefinierte Verhalten". Wenn andere Sprachen versagen, verhält sich c / c ++ "undefiniert" :) Das ist sicherlich ein großer Teil ihres Charmes. Und ich mache keine Witze.
Shylent
6

Es bezieht sich nicht auf eine leere Zeile, sondern darauf, ob die letzte Zeile (die Inhalt enthalten kann) mit einer neuen Zeile abgeschlossen wird.

Die meisten Texteditoren setzen eine neue Zeile am Ende der letzten Zeile einer Datei. Wenn also in der letzten Zeile keine vorhanden ist, besteht die Gefahr, dass die Datei abgeschnitten wurde. Es gibt jedoch triftige Gründe, warum Sie die neue Zeile möglicherweise nicht möchten, sodass es sich nur um eine Warnung und nicht um einen Fehler handelt.

Leigh Caldwell
quelle
5

#includeersetzt seine Zeile durch den wörtlichen Inhalt der Datei. Wenn die Datei nicht mit einer neuen Zeile endet, wird die Zeile mit der Zeile, die sie #includeeingezogen hat, mit der nächsten Zeile zusammengeführt.

Mondschatten
quelle
2

Ich verwende die c-freie IDE-Version 5.0. In meinem Programm mit der Sprache 'c ++' oder 'c' trat das gleiche Problem auf. Nur am Ende des Programms, dh in der letzten Zeile des Programms (nach Klammern der Funktion) Haupt- oder eine beliebige Funktion), drücken Sie die Eingabetaste . wird um 1 erhöht. Wenn Sie dasselbe Programm ausführen, wird es ohne Fehler ausgeführt.

Divesh
quelle
2

In der Praxis fügt natürlich jeder Compiler nach dem #include eine neue Zeile hinzu. Gott sei Dank. - @mxcl

GL_ARB_shading_language_includeKein spezifisches C / C ++, sondern ein C-Dialekt: Wenn Sie die Erweiterung verwenden, warnt Sie der glsl-Compiler unter OS X NICHT vor einem fehlenden Zeilenumbruch. Sie können also eine MyHeader.hDatei mit einem Header Guard schreiben , der mit endet, #endif // __MY_HEADER_H__und Sie werden die Zeile nach dem #include "MyHeader.h"mit Sicherheit verlieren .

Jan-Philip Loos
quelle
2

Weil sich das Verhalten zwischen C / C ++ - Versionen unterscheidet, wenn die Datei nicht mit einer neuen Zeile endet. Besonders böse sind ältere C ++ - Versionen, fx in C ++ 03 sagt der Standard (Übersetzungsphasen):

Wenn eine Quelldatei, die nicht leer ist, nicht in einem Zeilenumbruchzeichen oder in einem Zeilenumbruchzeichen endet, dem unmittelbar ein Backslash-Zeichen vorangestellt ist, ist das Verhalten undefiniert.

Undefiniertes Verhalten ist schlecht: Ein standardkonformer Compiler kann hier mehr oder weniger das tun, was er will (schädlichen Code einfügen oder was auch immer) - eindeutig ein Grund zur Warnung.

Während die Situation in C ++ 11 besser ist, ist es eine gute Idee, Situationen zu vermeiden, in denen das Verhalten in früheren Versionen nicht definiert ist. Die C ++ 03-Spezifikation ist schlechter als C99, was solche Dateien völlig verbietet (das Verhalten wird dann definiert).

Himmel König
quelle
Ich vermute, der Standard sagte, dass Programme ohne die nachfolgende neue Zeile ein undefiniertes Verhalten haben, anstatt zu behaupten, dass sie fehlerhaft waren, da einige Compiler eine nicht terminierte letzte Zeile einer enthaltenen Datei mit dem Quellcodetext verketten würden, der der #includeAnweisung folgt Einige Programmierer, die auf solche Compiler abzielen, haben dieses Verhalten möglicherweise ausgenutzt. Wenn der Standard solche Dinge undefiniert lässt, können Programme, die solche Macken ausnutzen, auf Plattformen, die ein solches Verhalten spezifizieren, genau definiert werden. Wenn das Standardmandat ein Verhalten hätte, würde dies solche Programme brechen.
Supercat
0

Diese Warnung kann auch dazu beitragen, anzuzeigen, dass eine Datei möglicherweise abgeschnitten wurde. Es ist wahr, dass der Compiler wahrscheinlich sowieso einen Compilerfehler auslösen wird - insbesondere wenn er sich mitten in einer Funktion befindet - oder vielleicht einen Linkerfehler, aber diese könnten kryptischer sein und können nicht garantiert auftreten.

Natürlich ist diese Warnung auch nicht garantiert, wenn die Datei unmittelbar nach einem Zeilenumbruch abgeschnitten wird. In einigen Fällen kann es jedoch vorkommen, dass andere Fehler übersehen werden, und es wird ein stärkerer Hinweis auf das Problem gegeben.

mwfearnley
quelle
-2

Das ist kein Fehler. Es ist nur eine Warnung.

Öffnen Sie die Datei in einem Editor, gehen Sie zur letzten Zeile der Datei und drücken Sie die Eingabetaste, um am Ende der Datei eine leere Zeile einzufügen.

Abgesehen davon sollten Sie jedoch #include <iostream>anstelle von verwenden <iostream.h>. Dann setzen Sie ein using std::cout;danach.

keya
quelle