preprocessing directive with no new-line character

Martin Sebor msebor@gmail.com
Tue Jul 18 23:43:00 GMT 2017


On 07/18/2017 02:46 PM, Dennis Clarke wrote:
>
>>>> Do you have 0x0A at the end of your text file ?
>>>
>>> No:
>>>
>>> zira:~> hd tst.c
>>> 00000000  69 6e 74 20 6d 61 69 6e  20 28 76 6f 69 64 29 0a  |int main
>>> (void).|
>>> 00000010  7b 0a 20 20 72 65 74 75  72 6e 20 30 3b 0a 7d 0a  |{.
>>> return 0;.}.|
>>> 00000020  23 64 65 66 69 6e 65 20  46 4f 4f                 |#define
>>> FOO|
>>> 0000002b
>>>
>>> And BTW, Clang behaves as expected:
>>>
>>> zira:~> clang-4.0 -std=c99 -pedantic tst.c -o tst
>>> tst.c:5:12: warning: no newline at end of file [-Wnewline-eof]
>>> #define FOO
>>>            ^
>>> 1 warning generated.
>>>
>>> So, I think that's a bug in GCC. Do you agree?
>>
>> I agree.  C requires non-empty source files to end in an unescaped
>> new-line character.  POSIX further requires that source files be
>> text files (and defines the term text file as a file organized
>> into zero or more lines of at most LINE_MAX characters each).
>>
>> C++ 11 (and later) has a weaker requirement that makes the above
>> test case valid.
>
> Fascinating. I never would have thought that a zero line length file
> would be accepted as valid. However gcc ( older rev 4.9.2 ) will
> accept this :
>
> $ printf "int main ( int argc, char* argv[] ) { return 0; }" > tzero.c
>
> $ wc tzero.c
>        0      12      49 tzero.c
>
> $ hdump -Ax -v -tx1 tzero.c
>      0:  69 6e 74 20 6d 61 69 6e 20 28 20 69 6e 74 20 61
>     10:  72 67 63 2c 20 63 68 61 72 2a 20 61 72 67 76 5b
>     20:  5d 20 29 20 7b 20 72 65 74 75 72 6e 20 30 3b 20
>     30:  7d
>     31:
>
> $ /usr/local/gcc4/bin/gcc -m64 -std=c99 -pedantic \
>> -D_TS_ERRNO -D_POSIX_PTHREAD_SEMANTICS \
>> -D_LARGEFILE64_SOURCE -S -o tzero.s tzero.c
>
> $ cat tzero.s
>         .file   "tzero.c"
>         .section        ".text"
>         .align 4
>         .global main
>         .type   main, #function
>         .proc   04
> main:
>         save    %sp, -176, %sp
>         mov     %i0, %g1
>         stx     %i1, [%fp+2183]
>         st      %g1, [%fp+2175]
>         mov     0, %g1
>         sra     %g1, 0, %g1
>         mov     %g1, %i0
>         return  %i7+8
>          nop
>         .size   main, .-main
>         .ident  "GCC: (genunix Fri Jan  2 11:56:03 GMT 2015) 4.9.2"
>
>
> Whereas c99 ( Oracle Studio 12.4 ) rejects the input file :
>
> $ c99 -errfmt=error -erroff=%none -errshort=full \
>> -m64 -xmemalign=8s -xnolibmil -Xc -xregs=no%appl -xlibmieee \
>> -Qy -xbuiltin=%none -D_TS_ERRNO -D_POSIX_PTHREAD_SEMANTICS \
>> -D_LARGEFILE64_SOURCE -S -o tzero.s tzero.c
> "tzero.c", line 1: warning: newline not last character in file
>
> I think "zero or more lines of at most LINE_MAX characters each" won't
> work. There must be more than "zero lines" in the input.  What is the
> actual spec?

Yes, C requires every non-empty source file to have at least
one line.  The C11 standard says in 5.1.1.2 Translation phases,
p2:

   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.

The POSIX specification for the c99 command specifies that its
input be a text file:

   pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_07

with Text File being defined here:

 
pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_403

The C++ requirement is also in Phases of translation:

   A source file that is not empty and that does not end in
   a new-line character, or that ends in a new-line character
   immediately preceded by a backslash character before any such
   splicing takes place, shall be processed as if an additional
   new-line character were appended to the file.

>
> This is really splitting hairs of course.

It actually has been a source of subtle bugs.  POSIX defines
the behavior of most utilities (e.g., awk, grep, and sed) for
text files but not for others.  Some implementations (I think
even some GNU utilities) don't behave the same way when their
input doesn't meet that requirement.  Being undefined, their
behavior can be pretty bizarre (i.e., it's not constrained
to justnot processing the remainder of the file past the last
newline, but can extend to the lines prior to it).

Martin



More information about the Gcc-help mailing list