5

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

iBug
  • 35,554
  • 7
  • 89
  • 134
msc
  • 33,420
  • 29
  • 119
  • 214

4 Answers4

4

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.

M.M
  • 138,810
  • 21
  • 208
  • 365
2

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.

supercat
  • 77,689
  • 9
  • 166
  • 211
2

I believe gcc is non-conforming.

Regardless of how one may reason about the part in 5.1.1.2 not being a constraint, gcc also allows this non-conforming program:

#include <stdio.h> /* no new line here */

This is a pre-processing directive. C17 6.10 §2 defines a pre-processing directive as (bold emphasis mine):

A preprocessing directive consists of a sequence of preprocessing tokens that satisfies the following constraints: The first token in the sequence is a # preprocessing token that (at the start of translation phase 4) is either the first character in the source file (optionally after white space containing no new-line characters) or that follows white space containing at least one new-line character. The last token in the sequence is the first newline character that follows the first token in the sequence. A new-line character ends the preprocessing directive even if it occurs within what would otherwise be an invocation of a function-like macro.

Furthermore 6.10 §5

Constraints
The only white-space characters that shall appear between preprocessing tokens within a preprocessing directive (from just after the introducing # preprocessing token through just before the terminating new-line character) ...

This text is supported by formal syntax in 6.10:

control-line:
# include pp-tokens new-line

new-line:
the new-line character

An implementation is required to issue a diagnostic message in this situation:

5.1.1.3 Diagnostics
A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, ...

Silently allowing #include <stdio.h> /* no new line here */ without any diagnostic even in -pedantic mode renders gcc non-conforming since there is (arguably) a constraint violation of 6.10 §5 as well as definitely a syntax rule violation of the syntax listed in 6.10.

The clang compiler behaves correctly.

Lundin
  • 195,001
  • 40
  • 254
  • 396
1

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)

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • Note that the standard does not say the compiler must emit a warning in this case – M.M Nov 22 '17 at 09:35
  • I have not gone to the standard to see how it does.... The only thing here to say is that the C standard talks about source code, and not how it is stored on a system or the preparation it has to be done for the file to be correctly parsed. Suppose an EBCDIC system with fixed (Hollerith) length lines, and no endline characters. How can be run a C compiler on it? People tend to translate their own environments to the standard without reading the first paragraphs of it, that normally say something like I'm telling now. – Luis Colorado Nov 22 '17 at 09:38
  • Suppose a system that knows about text files and stores them as a binary number indicating the length line and no newline character. The compiler (or some other tool) will need to convert file format so the source code can appear and be feed correctly to the compiler. – Luis Colorado Nov 22 '17 at 09:42
  • Oh I agree completely with that line of reasoning too. I feel your first paragraph might be misread as claiming gcc is non-compliant. – M.M Nov 22 '17 at 09:45
  • My paragraph is a conditional... _if it behaves as you say, then..._ – Luis Colorado Nov 22 '17 at 10:02
  • You said "if the standard says the compiler must issue a warning", not "if it behaves as you say". The compiler does behave as OP says, but the standard does not say the compiler must issue a warning, and OP should not file a compliance issue. The wording you use in your second sentence is normally only used in English when the thing following the word "if" is actually true. It would be better to use the subjunctive, or leave out the sentence entirely (since it's tautological that a compliance issue should be reported if it exists) – M.M Nov 22 '17 at 20:03
  • The fact is that I have not read the standard for this issue, and I'm trusting the question formulated for truthness.... that's the reason I made that conditional, and I don't change my reasoning... should the standard had said that, the compilation of a non `\n` terminated source should have given the required message. – Luis Colorado Nov 30 '17 at 12:13