Ostrzeżenie kompilatora „Brak nowej linii na końcu pliku”

187

Jaki jest powód następującego ostrzeżenia w niektórych kompilatorach C ++?

Brak nowego wiersza na końcu pliku

Dlaczego powinienem mieć pustą linię na końcu pliku źródłowego / nagłówka?

Brian Tompsett - 汤 莱恩
źródło
17
Naprawdę nie jest to powód, ale jest to bardzo denerwujące, jeśli masz catplik i nie ma on końca nowej linii, ponieważ monit o nową powłokę pojawi się po ostatnim wierszu pliku (tj. Nie w kolumnie 0)
ThiefMaster
@ ThiefMaster My $ PS1 zaczyna się od nowej linii z tego właśnie powodu. (i tak jest to wieloliniowy monit, zawierający kilka przydatnych informacji w jednym wierszu, a następnie tylko znak zachęty w następnym, aby dość długie polecenia się nie
zawijały
7
Why should I have an empty line at the end of a source/header file- Jeśli plik tekstowy zawiera, one\ntwo\nthree\nwówczas zawiera trzy wiersze, z których żaden nie jest pusty. Jeśli plik tekstowy zawiera one\ntwo\nthree, to nie jest to plik tekstowy, w tym samym sensie, że zdanie bez kropki na końcu nie jest zdaniem.
Brandin

Odpowiedzi:

217

Pomyśl o niektórych problemach, które mogą wystąpić, jeśli nie ma nowej linii. Zgodnie ze standardem ANSI #includeplik na początku wstawia plik dokładnie tak, jak jest na początku pliku i nie wstawia nowego wiersza po #include <foo.h>zawartości pliku. Jeśli więc do analizatora składni zostanie dołączony plik bez nowej linii na końcu, zostanie on wyświetlony tak, jakby ostatni wiersz znajdował się foo.hw tym samym wierszu, co pierwszy wiersz foo.cpp. Co jeśli ostatni wiersz foo.h był komentarzem bez nowego wiersza? Teraz pierwszy wiersz foo.cppjest skomentowany. To tylko kilka przykładów rodzajów problemów, które mogą się wkraść.


Chciałem tylko wskazać zainteresowanym stronom odpowiedź Jamesa poniżej. Chociaż powyższa odpowiedź jest nadal poprawna dla C, nowy standard C ++ (C ++ 11) został zmieniony, tak że to ostrzeżenie nie powinno być dłużej wyświetlane, jeśli używasz C ++ i kompilatora zgodnego z C ++ 11.

Ze standardu C ++ 11 za pośrednictwem posta Jamesa:

Plik źródłowy, który nie jest pusty i nie kończy się znakiem nowej linii lub kończy się znakiem nowej linii bezpośrednio poprzedzonym znakiem odwrotnego ukośnika, zanim nastąpi takie splicowanie, będzie przetwarzany tak, jakby dodatkowy nowy- do pliku dołączono znaki wiersza (C ++ 11 §2.2 / 1).

TJ Seabrooks
źródło
28
Oczywiście w praktyce każdy kompilator dodaje nowy wiersz po #include. Na szczęście
mxcl,
3
Pamiętam, że stara wersja Microsoft Visual C ++ (jak 2.x lub coś takiego) miała dokładnie ten problem. Zostało to zaostrzone, ponieważ edytor IDE zachęcał do tego rodzaju zachowania polegającego na braku nowej linii.
Greg Hewgill,
2
Kompilatory mogą obecnie nie narzekać, ale GitHub tak robi.
Puyover
1
Widzę odpowiedź Jamesa „poniżej”, ale: „Powyższa odpowiedź” w OrderBy co ?! Powyżej jest pytanie, jak zwykle zamawiam głosami. Czy masz na myśli własną odpowiedź?
mbx
@ Thomas: Czy ten program wywołuje niezdefiniowane zachowanie, ponieważ nie kończy się na nowej linii. Zobacz program tutaj: ideone.com/jswwf9
Destructor
44

Wymóg, aby każdy plik źródłowy kończył się nieoznakowanym znakiem nowej linii został usunięty w C ++ 11. Specyfikacja brzmi teraz:

Plik źródłowy, który nie jest pusty i nie kończy się znakiem nowej linii lub kończy się znakiem nowej linii bezpośrednio poprzedzonym znakiem odwrotnego ukośnika, zanim nastąpi takie splicowanie, będzie przetwarzany tak, jakby dodatkowy nowy- do pliku dołączono znaki wiersza (C ++ 11 §2.2 / 1).

Kompilator zgodny nie powinien już wydawać tego ostrzeżenia (przynajmniej nie podczas kompilacji w trybie C ++ 11, jeśli kompilator ma tryby dla różnych wersji specyfikacji języka).

James McNellis
źródło
4
To wszystko dobrze i dobrze dla C ++; niestety C nadal twierdzi, że jest to UB, nawet w najnowszej wersji nadchodzącego standardu C1X.
Adam Rosenfield,
11
To pytanie jest oznaczone jako [c ++], a nie [c].
James McNellis,
3
Mimo to prawdopodobnie powinien być oznaczony [c], ponieważ wiele osób szukających tego ostrzeżenia w C znajdzie tutaj swoją drogę.
Adam Rosenfield,
1
To nadal dobry punkt do dodania. Dodając to powyżej. Mam nadzieję, że nie masz nic przeciwko.
TJ Seabrooks,
25

C ++ 03 Standard [2.1.1.2] deklaruje:

... Jeśli plik źródłowy, który nie jest pusty, nie kończy się znakiem nowego wiersza lub kończy się znakiem nowego wiersza bezpośrednio poprzedzonym znakiem odwrotnego ukośnika przed wystąpieniem takiego łączenia, zachowanie jest niezdefiniowane.

Igor Semenow
źródło
16

Odpowiedź na „posłuszny” brzmi „ponieważ standard C ++ 03 mówi, że zachowanie programu nie kończącego się na nowej linii jest niezdefiniowane” (parafraza).

Odpowiedź dla ciekawskich znajduje się tutaj: http://gcc.gnu.org/ml/gcc/2001-07/msg01120.html .

Vytautas Shaltenis
źródło
4
Ahh, ukochane „niezdefiniowane zachowanie”. Gdy inne języki zawodzą, c / c ++ zachowują się w „nieokreślony” sposób :) To z pewnością duża część ich uroku. I nie żartuję.
shylent
6

Nie odnosi się do pustej linii, chodzi o to, czy ostatni wiersz (który może zawierać treść) kończy się nową linią.

Większość edytorów tekstu umieszcza nowy wiersz na końcu ostatniego wiersza pliku, więc jeśli ostatni wiersz go nie ma, istnieje ryzyko, że plik został obcięty. Istnieją jednak ważne powody, dla których możesz nie chcieć nowego wiersza, więc jest to tylko ostrzeżenie, a nie błąd.

Leigh Caldwell
źródło
5

#includezastąpi jego linię dosłowną zawartością pliku. Jeśli plik nie kończy się na nowej linii, linia zawierająca tę, #includektóra go wciągnęła, połączy się z kolejną linią.

księżycowy cień
źródło
2

Korzystam z c-free IDE w wersji 5.0, w moim programie albo w języku „c ++” albo „c” otrzymywałem ten sam problem, tylko na końcu programu, tj. W ostatnim wierszu programu (po nawiasach funkcji może to być główna lub dowolna funkcja), naciśnij enter -line no. zostanie zwiększona o 1. następnie uruchom ten sam program, będzie działał bezbłędnie.

nurkować
źródło
2

Oczywiście w praktyce każdy kompilator dodaje nowy wiersz po #include. Na szczęście - @mxcl

nie konkretny C / C ++, ale dialekt C: podczas korzystania z GL_ARB_shading_language_includerozszerzenia kompilator glsl w OS X ostrzega NIE o brakującym nowym wierszu . Więc można napisać MyHeader.hplik z osłoną nagłówka, który kończy się #endif // __MY_HEADER_H__i będzie tracić linię po #include "MyHeader.h"na pewno.

Jan-Philip Loos
źródło
2

Ponieważ zachowanie różni się między wersjami C / C ++, jeśli plik nie kończy się na nowej linii. Szczególnie nieprzyjemne są starsze wersje C ++, fx w C ++ 03 standard mówi (fazy tłumaczenia):

Jeśli plik źródłowy, który nie jest pusty, nie kończy się znakiem nowej linii lub kończy się znakiem nowej linii bezpośrednio poprzedzonym znakiem ukośnika odwrotnego, zachowanie jest niezdefiniowane.

Niezdefiniowane zachowanie jest złe: kompilator zgodny ze standardem mógłby zrobić mniej więcej to, czego chce tutaj (wstawić złośliwy kod lub cokolwiek innego) - wyraźnie powód ostrzeżenia.

Chociaż sytuacja jest lepsza w C ++ 11, dobrym pomysłem jest unikanie sytuacji, w których zachowanie jest niezdefiniowane we wcześniejszych wersjach. Specyfikacja C ++ 03 jest gorsza niż C99, która wprost zabrania takich plików (następnie definiowane jest zachowanie).

Król nieba
źródło
Podejrzewam, że Standard powiedział, że programy bez końcowego wiersza mają niezdefiniowane zachowanie, zamiast stwierdzać, że były źle sformułowane, ponieważ niektóre kompilatory połączyłyby nie kończący się ostatni wiersz dołączonego pliku z tekstem kodu źródłowego zgodnie z #includedyrektywą , a niektórzy programiści atakujący takie kompilatory mogli wykorzystać takie zachowanie. Pozostawienie Standardowego pozostawienia takich niezdefiniowanych elementów pozwoliłoby dobrze zdefiniować programy wykorzystujące takie dziwactwa na platformach, które określają takie zachowanie. Posiadanie standardowego mandatu spowodowałoby uszkodzenie takich programów.
supercat
0

To ostrzeżenie może również pomóc wskazać, że plik mógł zostać w jakiś sposób obcięty. Prawdą jest, że kompilator prawdopodobnie i tak wyrzuci błąd kompilatora - szczególnie jeśli znajduje się w środku funkcji - lub może błąd linkera, ale mogą one być bardziej tajemnicze i nie ma gwarancji, że wystąpią.

Oczywiście to ostrzeżenie nie jest również gwarantowane, jeśli plik zostanie obcięty natychmiast po nowej linii, ale nadal może wychwycić niektóre przypadki, w których inne błędy mogą zostać pominięte, i daje silniejszą wskazówkę na temat problemu.

mwfearnley
źródło
-2

To nie jest błąd. To tylko ostrzeżenie.

Otwórz plik w edytorze, przejdź do ostatniego wiersza pliku i naciśnij klawisz Enter, aby dodać pusty wiersz na końcu pliku.

Chociaż poza tym powinieneś używać #include <iostream>zamiast <iostream.h>. Następnie włóż using std::cout;po nim.

keya
źródło