Предупреждение компилятора «Нет новой строки в конце файла»

187

В чем причина следующего предупреждения в некоторых компиляторах C ++?

Нет новой строки в конце файла

Почему у меня должна быть пустая строка в конце файла источника / заголовка?

Брайан Томпсетт - 汤 莱恩
источник
17
Не совсем причина, но это очень раздражает, если вы catфайл, и у него нет завершающего символа новой строки, так как новое приглашение оболочки появится после последней строки файла (т.е. не в столбце 0)
ThiefMaster
@ThiefMaster Мой $ PS1 начинается с новой строки именно по этой причине. (в любом случае это многострочная подсказка, содержащая кучу полезной информации в одной строке, а затем ничего, кроме символа подсказки в следующей строке, чтобы довольно длинные команды не
переносились
7
Why should I have an empty line at the end of a source/header file- Если текстовый файл содержит, one\ntwo\nthree\nто он содержит три строки, ни одна из которых не является пустой. Если текстовый файл содержит, one\ntwo\nthreeто это не текстовый файл, в том смысле, что предложение без полной остановки в конце не является предложением.
Брандин

Ответы:

217

Подумайте о некоторых проблемах, которые могут возникнуть при отсутствии новой строки. В соответствии со стандартом ANSI #includeфайл в начале вставляет файл точно так, как он находится в начале файла, и не вставляет новую строку #include <foo.h>после содержимого файла после. Поэтому, если вы добавите в парсер файл без перевода строки в конце, он будет выглядеть так, как будто последняя строка foo.hнаходится на той же строке, что и первая строка foo.cpp. Что если в последней строке foo.h был комментарий без новой строки? Теперь первая строка foo.cppзакомментирована. Это всего лишь пара примеров типов проблем, которые могут возникнуть.


Просто хотел указать любым заинтересованным сторонам на ответ Джеймса ниже. Хотя приведенный выше ответ все еще корректен для C, новый стандарт C ++ (C ++ 11) был изменен, так что это предупреждение больше не должно появляться, если используется C ++ и компилятор, соответствующий C ++ 11.

Из стандарта C ++ 11 через сообщение Джеймса:

Исходный файл, который не является пустым и не оканчивается символом новой строки или заканчивается символом новой строки, которому непосредственно предшествует символ обратной косой черты, до того, как произойдет любое такое соединение, должен обрабатываться так, как если бы дополнительный новый символ строки был добавлен в файл (C ++ 11 §2.2 / 1).

TJ Сибрукс
источник
28
Конечно, на практике каждый компилятор добавляет новую строку после #include. К счастью.
mxcl
3
Я помню, что старая версия Microsoft Visual C ++ (например, 2.x или что-то еще) имела именно эту проблему. Это усугубилось тем, что редактор IDE поощрял такого рода поведение при отсутствии новой строки.
Грег Хьюгилл
2
Компиляторы могут не жаловаться в настоящее время, но GitHub фактически делает.
Puyover
1
Я вижу ответ «ниже» Джеймса, но: «Ответ выше» в OrderBy что ?! Выше вопрос, как я обычно заказываю голосами. Или ты имеешь ввиду свой ответ?
mbx
@Thomas: эта программа вызывает неопределенное поведение, потому что оно не заканчивается новой строкой. Смотрите программу здесь: ideone.com/jswwf9
Деструктор
44

Требование, чтобы каждый исходный файл заканчивался не экранированным символом новой строки, было удалено в C ++ 11. Спецификация теперь гласит:

Исходный файл, который не является пустым и не оканчивается символом новой строки или заканчивается символом новой строки, которому непосредственно предшествует символ обратной косой черты, до того, как произойдет любое такое соединение, должен обрабатываться так, как если бы дополнительный новый символ строки был добавлен в файл (C ++ 11 §2.2 / 1).

Соответствующий компилятор больше не должен выдавать это предупреждение (по крайней мере, при компиляции в режиме C ++ 11, если у компилятора есть режимы для разных ревизий спецификации языка).

Джеймс МакНеллис
источник
4
Это все хорошо для C ++; к сожалению, C до сих пор говорит, что это UB, даже в последней версии готовящегося стандарта C1X.
Адам Розенфилд
11
Этот вопрос помечен [c ++], а не [c].
Джеймс МакНеллис
3
Тем не менее, он, вероятно, должен быть помечен [c], так как многие люди, ищущие это предупреждение в C, найдут здесь свой путь.
Адам Розенфилд
1
Это еще хороший момент, чтобы добавить. Добавляя это выше. Надеюсь, ты не возражаешь.
TJ Сибрукс
25

Стандарт C ++ 03 [2.1.1.2] объявляет:

... Если исходный файл, который не является пустым, не заканчивается символом новой строки или оканчивается символом новой строки, которому непосредственно предшествует символ обратной косой черты, прежде чем произойдет любое такое соединение, поведение не определено.

Игорь Семенов
источник
16

Ответ для «послушного» - «потому что стандарт C ++ 03 говорит, что поведение программы, не заканчивающейся переводом строки, не определено» (перефразировано).

Ответ для любопытных находится здесь: http://gcc.gnu.org/ml/gcc/2001-07/msg01120.html .

Витаутас Шалтенис
источник
4
Ааа, любимое "неопределенное поведение". Когда другие языки терпят неудачу, c / c ++ ведет себя «неопределенным» образом :) Это, безусловно, большая часть их обаяния. И я не шучу.
Shylent
6

Это не относится к пустой строке, а к тому, заканчивается ли последняя строка (которая может содержать содержимое) новой строкой.

Большинство текстовых редакторов помещают новую строку в конец последней строки файла, поэтому, если в последней строке ее нет, существует риск, что файл был усечен. Тем не менее, существуют веские причины, по которым вам может не понадобиться перевод строки, поэтому это всего лишь предупреждение, а не ошибка.

Ли Колдуэлл
источник
5

#includeзаменит свою строку на буквальное содержимое файла. Если файл не заканчивается новой строкой, строка, содержащая #includeего, объединится со следующей строкой.

Лунная тень
источник
2

Я использую c-free IDE версии 5.0, в моей программе на языке «c ++» или «c» у меня возникла та же проблема. Просто в конце программы, т.е. в последней строке программы (после скобок функции это может быть основной или любой другой функции), нажмите enter- line no. будет увеличен на 1. затем выполнить ту же программу, она будет работать без ошибок.

divesh
источник
2

Конечно, на практике каждый компилятор добавляет новую строку после #include. К счастью. - @mxcl

не конкретный C / C ++, а диалект C: при использовании GL_ARB_shading_language_includeрасширения компилятор glsl в OS X предупреждает вас НЕ о пропущенном переводе строки. Таким образом, вы можете написать MyHeader.hфайл с заголовком, который заканчивается на, #endif // __MY_HEADER_H__и вы наверняка потеряете строку после #include "MyHeader.h".

Ян-Филипп Лоос
источник
2

Потому что поведение отличается в версиях C / C ++, если файл не заканчивается новой строкой. Особенно неприятны старые C ++ - версии, fx в C ++ 03 стандарт говорит (фазы перевода):

Если исходный файл, который не является пустым, не заканчивается символом новой строки или заканчивается символом новой строки, которому непосредственно предшествует символ обратной косой черты, поведение не определено.

Неопределенное поведение - это плохо: стандартный соответствующий компилятор может делать более или менее то, что он хочет здесь (вставлять вредоносный код или что-то в этом роде) - очевидно, причина для предупреждения.

Хотя в C ++ 11 ситуация лучше, рекомендуется избегать ситуаций, когда поведение не определено в более ранних версиях. Спецификация C ++ 03 хуже, чем C99, которая категорически запрещает такие файлы (затем определяется поведение).

skyking
источник
Я подозреваю, что Стандарт сказал, что программы без завершающей новой строки имеют Undefined Behavior, вместо того, чтобы утверждать, что они были неправильно сформированы, потому что некоторые компиляторы объединяли бы не завершенную последнюю строку включенного файла с текстом исходного кода после #includeдирективы и некоторые программисты, нацеленные на такие компиляторы, могли использовать такое поведение. Если в стандарте оставить такие вещи неопределенными, это позволит программам, использующим такие причуды, быть четко определенными на платформах, которые определяют такое поведение. При наличии стандартного мандата поведение нарушит такие программы.
суперкат
0

Это предупреждение может также помочь указать, что файл мог быть как-то урезан. Это правда, что компилятор, вероятно, все равно выдаст ошибку компилятора - особенно если он находится в середине функции - или, возможно, ошибку компоновщика, но они могут быть более загадочными и не гарантированно произойдут.

Конечно, это предупреждение также не гарантируется, если файл обрезается сразу после новой строки, но оно все равно может отлавливать некоторые случаи, которые могут пропустить другие ошибки, и дает более сильный намек на проблему.

mwfearnley
источник
-2

Это не ошибка. Это просто предупреждение.

Откройте файл в редакторе, перейдите к последней строке файла и нажмите клавишу ввода, чтобы добавить пустую строку в конец файла.

Хотя, кроме того, вы должны использовать #include <iostream>вместо <iostream.h>. Тогда вставьте using std::cout;после этого.

Keya
источник