Why does auto a=1; compile in C?
This is both an answer and an extended comment to No, this isn't legal C since 1999. No decent modern C compiler allows for this.
Yes, auto a=1;
is illegal in C1999 (and also C2011). Just because this is now illegal does not mean that a modern C compiler should reject code that contains such constructs. I would argue exactly the opposite, that a decent modern C compiler must still allow for this.
Both clang and gcc do just that when compiling the sample code in the question against the 1999 or 2011 versions of the standard. Both compilers issue a diagnostic and then carry on as if the objectionable statement had been auto int a=1;
.
In my opinion, this is what a decent compiler should do. By issuing a diagnostic, clang and gcc are full compliant with the standard. The standard does not say that a compiler must reject illegal code. The standard merely says that a conforming implementation must produce at least one diagnostic message if a translation unit contains a violation of any syntax rule or constraint (5.1.1.3).
Given code that contains illegal constructs, any decent compiler will try to make sense of the illegal code so that the compiler can find the next error in the code. A compiler that stops at the first error isn't a very good compiler. There is a way to make sense out of auto a=1
, which is to apply the "implicit int" rule. This rule forces the compiler to interpret auto a=1
as if it were auto int a=1
when the compiler is used in C90 or K&R mode.
Most compilers typically do reject code (reject: refuse to generate an object file or an executable) that contains illegal syntax. This is a case where the compiler authors decided that failing to compile is not the best option. The best thing to do is to issue a diagnostic, fix the code, and carry on. There's just too much legacy code that is peppered with constructs such as register a=1;
. The compiler should be able to compile that code in C99 or C11 mode (with a diagnostic, of course).
auto
is an old C keyword that means "local scope". auto a
is the same as auto int a
, and because local scope is the default for a variable declared inside a function, it's also the same as int a
in this example.
This keyword is actually a leftover from C's predecessor B, where there were no base types: everything was int
, pointer to int
, array of int
.(*) Declarations would be either auto
or extrn
[sic]. C inherited the "everything is int
" as a default rule, so you could declare integers with
auto a;
extern b;
static c;
ISO C got rid of this, but many compilers still accept it for backward compatibility. If it seems unfamiliar, then you should realise that a related rule is at work in
unsigned d; // actually unsigned int
which is still common in modern code.
C++11 reused the keyword, which few if any C++ programmers were using with the original meaning, for its type inference. This is mostly safe because the "everything is int
" rule from C had already been dropped in C++98; the only thing that breaks is auto T a
, which no-one was using anyway. (Somewhere in his papers on the history of the language, Stroustrup comments on this, but I can't find the exact reference right now.)
(*) String handling in B was interesting: you'd use arrays of int
and pack multiple characters in each member. B was actually BCPL with different syntax.