Advertencia del compilador "No hay nueva línea al final del archivo"

187

¿Cuál es la razón de la siguiente advertencia en algunos compiladores de C ++?

No hay nueva línea al final del archivo

¿Por qué debería tener una línea vacía al final de un archivo de origen / encabezado?

Brian Tompsett - 汤 莱恩
fuente
17
No es realmente la razón, pero es muy molesto si tiene catun archivo y no tiene una nueva línea final ya que el nuevo indicador de shell aparecerá después de la última línea del archivo (es decir, no en la columna 0)
ThiefMaster
@ThiefMaster My $ PS1 comienza con una nueva línea por esa misma razón. (de todos modos, es un mensaje de varias líneas, que contiene un montón de información útil en una línea y luego nada más que un carácter de solicitud en la siguiente para que los comandos bastante largos no se envuelvan)
bames53
77
Why should I have an empty line at the end of a source/header file- Si un archivo de texto contiene, one\ntwo\nthree\nentonces contiene tres líneas, ninguna de las cuales está vacía. Si un archivo de texto contiene, one\ntwo\nthreeentonces no es un archivo de texto, en el mismo sentido que una oración sin un punto final al final no es una oración.
Brandin

Respuestas:

217

Piense en algunos de los problemas que pueden ocurrir si no hay una nueva línea. De acuerdo con el estándar ANSI, el #includede un archivo al principio inserta el archivo exactamente como está al frente del archivo y no inserta la nueva línea #include <foo.h>después del contenido del archivo. Entonces, si incluye un archivo sin nueva línea al final del analizador, se verá como si la última línea de estuviera foo.hen la misma línea que la primera foo.cpp. ¿Qué pasaría si la última línea de foo.h fuera un comentario sin una nueva línea? Ahora foo.cppse comenta la primera línea de . Estos son solo algunos ejemplos de los tipos de problemas que pueden surgir.


Solo quería señalar a las partes interesadas la respuesta de James a continuación. Si bien la respuesta anterior sigue siendo correcta para C, el nuevo estándar C ++ (C ++ 11) se ha modificado para que esta advertencia ya no se emita si se usa C ++ y un compilador conforme a C ++ 11.

Desde el estándar C ++ 11 a través de la publicación de James:

Un archivo fuente que no esté vacío y que no termine en un carácter de nueva línea, o que termine en un carácter de nueva línea precedido inmediatamente por un carácter de barra diagonal inversa antes de que se produzca dicho empalme, como si se tratara de un nuevo Se agregaron caracteres de línea al archivo (C ++ 11 §2.2 / 1).

TJ Seabrooks
fuente
28
Por supuesto, en la práctica, cada compilador agrega una nueva línea después del #include. Agradecidamente.
mxcl
3
Recuerdo que una versión anterior de Microsoft Visual C ++ (como 2.xo algo) tenía exactamente este problema. Se exacerbó porque el editor IDE alentó este tipo de comportamiento de línea faltante.
Greg Hewgill el
2
Los compiladores pueden no quejarse actualmente, pero GitHub sí lo hace.
Puyover
1
Puedo ver la respuesta "a continuación" de James pero: "La respuesta anterior" en OrderBy what ?! Arriba está la pregunta, como suelo ordenar por votos. ¿O quieres decir tu propia respuesta?
mbx
@Thomas: ¿Este programa invoca un comportamiento indefinido porque no termina con una nueva línea? Ver programa aquí: ideone.com/jswwf9
Destructor
44

El requisito de que cada archivo de origen finalice con una nueva línea sin escape se eliminó en C ++ 11. La especificación ahora dice:

Un archivo fuente que no esté vacío y que no termine en un carácter de nueva línea, o que termine en un carácter de nueva línea precedido inmediatamente por un carácter de barra diagonal inversa antes de que se produzca dicho empalme, como si se tratara de un nuevo Se agregaron caracteres de línea al archivo (C ++ 11 §2.2 / 1).

Un compilador conforme ya no debería emitir esta advertencia (al menos no cuando compila en modo C ++ 11, si el compilador tiene modos para diferentes revisiones de la especificación del lenguaje).

James McNellis
fuente
44
Eso está muy bien para C ++; desafortunadamente, C todavía dice que es UB, incluso en el último borrador del próximo estándar C1X.
Adam Rosenfield
11
Esta pregunta está etiquetada [c ++] y no [c].
James McNellis
3
Aun así, probablemente debería etiquetarse [c], ya que muchas personas que buscan esta advertencia en C encontrarán su camino aquí.
Adam Rosenfield
1
Este sigue siendo un buen punto para agregar. Agregando esto arriba. Espero que no te importe.
TJ Seabrooks el
25

El estándar C ++ 03 [2.1.1.2] declara:

... Si un archivo de origen que no está vacío no termina en un carácter de nueva línea, o termina en un carácter de nueva línea precedido inmediatamente por un carácter de barra diagonal inversa antes de que se produzca dicho empalme, el comportamiento es indefinido.

Igor Semenov
fuente
16

La respuesta para el "obediente" es "porque el Estándar C ++ 03 dice que el comportamiento de un programa que no termina en nueva línea es indefinido" (parafraseado).

La respuesta para los curiosos está aquí: http://gcc.gnu.org/ml/gcc/2001-07/msg01120.html .

Vytautas Shaltenis
fuente
44
Ahh, el amado "comportamiento indefinido". Cuando otros lenguajes fallan, c / c ++ se comportan de manera "indefinida" :) Eso, ciertamente, es una gran parte de su encanto. Y no estoy bromeando.
shylent
6

No se refiere a una línea en blanco, es si la última línea (que puede tener contenido) está terminada con una nueva línea.

La mayoría de los editores de texto colocarán una nueva línea al final de la última línea de un archivo, por lo que si la última línea no tiene una, existe el riesgo de que el archivo se haya truncado. Sin embargo, hay razones válidas por las que es posible que no desee la nueva línea, por lo que es solo una advertencia, no un error.

Leigh Caldwell
fuente
5

#includereemplazará su línea con el contenido literal del archivo. Si el archivo no termina con una nueva línea, la línea que contiene el #includeque lo jaló se fusionará con la siguiente línea.

sombra de Luna
fuente
2

Estoy usando c-free IDE versión 5.0, en mi programa, ya sea del lenguaje 'c ++' o 'c', estaba teniendo el mismo problema. Justo al final del programa, es decir, la última línea del programa (después de llaves de función puede ser principal o cualquier función), presione enter -line no. se incrementará en 1. luego ejecute el mismo programa, se ejecutará sin error.

Divesh
fuente
2

Por supuesto, en la práctica, cada compilador agrega una nueva línea después del #include. Agradecidamente. - @mxcl

C / C ++ no específico, sino un dialecto C: cuando se usa la GL_ARB_shading_language_includeextensión, el compilador glsl en OS X le advierte que NO le falta una nueva línea. Por lo tanto se puede escribir un MyHeader.harchivo con un guardia de cabecera, que termina con #endif // __MY_HEADER_H__y usted va a perder la línea después del #include "MyHeader.h"seguro.

Jan-Philip Loos
fuente
2

Porque el comportamiento difiere entre las versiones de C / C ++ si el archivo no termina con nueva línea. Especialmente desagradable son las versiones anteriores de C ++, fx en C ++ 03 que el estándar dice (fases de traducción):

Si un archivo fuente que no está vacío no termina en un carácter de nueva línea, o termina en un carácter de nueva línea inmediatamente precedido por un carácter de barra diagonal inversa, el comportamiento es indefinido.

El comportamiento indefinido es malo: un compilador conforme estándar podría hacer más o menos lo que quiere aquí (insertar código malicioso o lo que sea), claramente un motivo de advertencia.

Si bien la situación es mejor en C ++ 11, es una buena idea evitar situaciones en las que el comportamiento no esté definido en versiones anteriores. La especificación C ++ 03 es peor que C99, lo que prohíbe directamente dichos archivos (el comportamiento se define luego).

Rey del cielo
fuente
Sospecho que el Estándar dijo que los programas sin la nueva línea final tienen Comportamiento indefinido, en lugar de afirmar que estaban mal formados, porque algunos compiladores concatenarían una línea final no terminada de un archivo incluido con el texto del código fuente siguiendo la #includedirectiva , y algunos programadores que se dirigen a dichos compiladores pueden haber explotado dicho comportamiento. Hacer que el Estándar deje tales cosas sin definir permitiría que los programas que exploten tales peculiaridades estén bien definidos en las plataformas que especifican dicho comportamiento. Tener el mandato estándar de un comportamiento rompería tales programas.
supercat
0

Esta advertencia también podría ayudar a indicar que un archivo podría haberse truncado de alguna manera. Es cierto que el compilador probablemente arrojará un error del compilador de todos modos, especialmente si está en el medio de una función, o tal vez un error de enlace, pero estos podrían ser más crípticos y no se garantiza que ocurran.

Por supuesto, esta advertencia tampoco está garantizada si el archivo se trunca inmediatamente después de una nueva línea, pero aún podría detectar algunos casos que podrían fallar otros errores y da una pista más clara del problema.

mwfearnley
fuente
-2

Eso no es un error. Es solo una advertencia.

Abra el archivo en un editor, vaya a la última línea del archivo y presione enter para agregar una línea en blanco al final del archivo.

Aunque, además de eso, deberías estar usando en #include <iostream>lugar de <iostream.h>. Luego pon un using std::cout;después.

keya
fuente