Why GCC doesn't generate any warnings about newline at end of file?

Viewed 1225

From C11 5.1.1.2 Translation phases:

Paragraph 2:

[...] A source file that is not empty shall end in a new-line character, which shall not be immediately preceded by a backslash character before any such splicing takes place.

It means every source file must end with a newline.

Example:

#include <stdio.h>

int main() 
{
    printf("Hello world\n");
    return 0;
}

Above example compiled on Clang using clang prog.c -Wall -Wextra -std=gnu11 -pedantic command. The compiler generates following warning:

prog.c:7:16: warning: no newline at end of file [-Wnewline-eof]
}
               ^

It's ok because there is no newline at the end of the source file.

Using gcc prog.c -Wall -Wextra -std=gnu11 -pedantic command, I compiled the above program on GCC. GCC doesn't generate any warning or error.

So, Why doesn't GCC generate any warning or error?

  1. Clang Live Demo

  2. GCC Live Demo

3 Answers

The meaning of "shall" is defined by section 4 point 2:

If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint or runtime-constraint is violated, the behavior is undefined.

The passage you quoted is not in a Constraints section. Therefore, if the source file does not end in a trailing newline then the program has undefined behaviour.

No diagnostic is required for undefined behaviour. The compiler is free to do anything. The GCC developers have probably decided to make the program behave as if there were a newline on the end and not bother the user with a warning.

The Standard does not specify any particular relationship between physical bytes stored on disk and the logical characters that make up a C program. If the source character set only uses codes 0x00-0x7E, for example, a conforming implementation might say that the first character of any line will have the upper bit set while foregoing any other kind of delimiter. Such an implementation would then be required to behave as though each line were followed by a newline character, even though no newline characters would appear in the source file (I don't think implementations are required to allow source lines that are completely blank to be represented in a way distinguishable from lines containing a single blank character).

If an implementation specifies that a text file consists of a number of lines separated by newline characters, and that an N-line file will contain N-1 newlines, it would be required to behave as though there was a newline character following the last byte in the file. If, however, the implementation specified that all valid text files end with a newline, it would be under no obligation when given an invalid text file that doesn't.

Note that, among other things, it's plausible that on some implementations, the first line following a #include will be concatenated to an incomplete line at the end of an included file. Such behavior, while quirky, might be useful in some cases and it's possible some code may have relied upon it. Given that such splicing, if unexpected, could have essentially unbounded consequences, leaving the behavior as Undefined is simpler than trying to categorize what might happen.

There's a problem, newlines are not well standard defined, as different systems have different new line conventions. But you are right... if the standard says a compiler must emit a warning in that case and gcc doesn't, it should be filed as a noncomplianance issue.

But I agree with @supercat's answer, in the sense that it can be assumed that a file without a final \n can be safely interpreted as a properly delimited text file with no line ending at the end... as the \n can be interpreted as a line separator character, and not a line ending one. In case this interpretation is valid, an empty file would be parsed as a one empty line file with no problem for the compiler to parse it, and no warning should be issued in that case. The same applies to any file without a final \n, and a file finished with a \n should be interpreted as a n + 1 lines file, with an extra empty line (this doesn't make any difference to the meaning of the C code inside, I'm afraid)

This will be probably the response you'll get in case you go to the gcc project to complain, so be prudent, but don't hesitate and do it.

By the way, have you tried to feed the compiler with a final \\ character (without a \nchar) the compiler is allowed to insert the final newline to simulate a properly defined file, but the preprocessor has to deal in a special form in case a \\ character is followed by a new line. In that case, the compiler should emit something, as you cannot continue past the last line of the file. Clang doesn't say anything in case the last line terminates in a \\ (that is a nonconformance) let's see what does gcc.... (sorry, I have no access to a gcc by now)

Related