127

The code:

int main(void)
{
    auto a=1;
    return 0;
}

gets compiled without errors by the MS Visual Studio 2012 compiler, when the file has the .c extension. I have always thought that when you use the .c extension, compilation should be according to the C syntax, and not C++. Moreover, as far as I know auto without a type is allowed only in C++ since C++11, where it means that the type is deduced from the initializer.

Does that mean that my compiler isn't sticking to C, or is the code actually correct in C-language?

MD XF
  • 7,062
  • 7
  • 34
  • 64
lee77
  • 1,463
  • 3
  • 10
  • 13
  • 8
    Either you compile with C++ mode (possible) or MS is still stuck in the last millenium. Implicit `int` has been removed from the C standard in 1999. – Jens Gustedt May 01 '14 at 11:41
  • 1
    `The code gets compiled without errors by the MS Visual Studio 2012 compiler` - what happens when you enable warnings? – Brandin May 01 '14 at 11:47
  • 16
    @JensGustedt MSVC++ only supports C89 (and a few features from C99). It's more of a C++ compiler. – ntoskrnl May 01 '14 at 12:35
  • 3
    @Brandin: With the /Wall option it gives warning C4431, saying that a type specifier is missing and that default int is no longer supported in C (see Jens' comment). It's a bit of a contradiction since obviously this compiler supports it... – lee77 May 01 '14 at 12:47
  • 4
    @JensGustedt By that measure, GCC 4.7, released 2012, (and later versions too, I suspect -- I don't have those at hand) is also "stuck in the last millenium". It compiles OP's code without even a notice when not given any flags. –  May 01 '14 at 13:19
  • 3
    @delnan, I was supposing at the least, that the OP had switched warning levels on. I obviously was wrong. And in a sense this is true, gcc also is still stuck there, since they still don't have C99 (or a variant) as default. clang warns about the construct, even without flags. – Jens Gustedt May 01 '14 at 13:25
  • MSFT have publicly stated that updating the C compiler shipped with Visual Studio is not even on their radar. It's why several open source projects that have to compile on both \*n?x and Windows are tied to C89. – kahen May 03 '14 at 23:50
  • This was asked in reddit http://www.reddit.com/r/programming/comments/24mvym/why_does_auto_a1_compile_in_c/ , #justsaying. – motiur May 05 '14 at 04:38
  • 1
    Thankfully MS have more recently changed their mind and said they will support C99. Took 'em long enough though... – Craig Ringer May 05 '14 at 06:18
  • 1
    @JensGustedt It's true that after 15 years, one could expect C99 as a default. On the other hand, this might just be recognizing reality: many people using C are stuck in the past. Unlike the C++ community (which is jumping on the C++11 bandwagon even before most compilers have time to implement it), most of the C community seems to be quite happy with C90, and to not be too interested in the C99 additions. – James Kanze May 06 '14 at 08:28

7 Answers7

242

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.

Fred Foo
  • 328,932
  • 68
  • 689
  • 800
  • 7
    No, this isn't legal C since 1999. No decent modern C compiler allows for this. – Jens Gustedt May 01 '14 at 11:40
  • 18
    @JensGustedt VS doesn't claim to provide a modern C compiler. From all appearances, work on the C compiler stopped many years ago; they only supply it so that people can continue to compile legacy code. (And of course, any decent modern C compiler will have options to support legacy code. Including an option for K&R C.) – James Kanze May 01 '14 at 11:50
  • And of course, B didn't run only on PDP-11, since it was developed before the PDP-11 existed. – James Kanze May 01 '14 at 11:54
  • @JamesKanze, this answer simply claims that untyped declarations would still be possible in "C", whatever the reader may understand by that term. This needs adjustment. – Jens Gustedt May 01 '14 at 11:58
  • 23
    @JensGustedt: are you sure? GCC and Clang both warn about it in C99 mode, but they don't consider it an error except with `-Werror`. – Fred Foo May 01 '14 at 12:12
  • @JamesKanze: I stand corrected about the platforms supported by B. – Fred Foo May 01 '14 at 12:13
  • I think the new gcc4.9 has an auto keyword which is identical to c++. – this May 01 '14 at 12:14
  • 1
    @self The [changelog](http://gcc.gnu.org/gcc-4.9/changes.html) says it's called `__auto_type`. – Fred Foo May 01 '14 at 12:16
  • That is what I was referring to. – this May 01 '14 at 12:20
  • If memory serves, the thing you can't do in C99 anymore is `a;` with *no* type specifiers or qualifiers whatsoever. `auto a;` is still valid and equivalent to `int a;` – zwol May 01 '14 at 13:17
  • 1
    @Zack `a;` was never a declaration, but a statement. – Fred Foo May 01 '14 at 13:19
  • 1
    @larsmans In the original K&R C, `a;` was a declaration, at least at file scope. – James Kanze May 01 '14 at 13:20
  • 1
    @Zack `auto a` is neither valid in C99 nor C11. – Jens Gustedt May 01 '14 at 13:27
  • 2
    @larsman, yes, in 6.7.2 there is an explicit constraint for that: *At least one type specifier shall be given in the declaration specifiers in each declaration ...* – Jens Gustedt May 01 '14 at 13:38
  • @JensGustedt: amended the answer. – Fred Foo May 01 '14 at 13:42
  • @JensGustedt MSVC supports only C89. – Archie May 01 '14 at 14:39
  • 40
    @JensGustedt - re *No, this isn't legal C since 1999. No decent modern C compiler allows for this.* The first statement is correct; it is illegal since 1999. IMHO, the second statement is incorrect. Any decent modern C compiler must allow for this. Look at all the legacy code that would have to be rewritten if they didn't allow for it. I've written an answer that expands on this comment. – David Hammen May 01 '14 at 14:49
  • 1
    @Jens A compiler is free to accept an otherwise incorrect program. Behavior is implementation defined in this case. – fuz May 03 '14 at 23:41
  • @JamesKanze *"VS doesn't claim to provide a modern C compiler"* Neither a modern C++ compiler, I think... – Manu343726 May 04 '14 at 17:36
  • 1
    @Manu343726 VS is a relatively modern C++ compiler. Perhaps not the best, but fairly good overall. The C compiler in VS, on the other hand, is only there to be able to compile legacy code, and doesn't really attempt to support anything more recent than C90. – James Kanze May 05 '14 at 15:45
  • @JamesKanze Not exactly, Microsoft actually added their own "safe" string handling functions, distinct from the ones in POSIX, and got these accepted into C11 as an optional library. So they implement part of C11, by virtue of having pushed their library into the standard. – Fred Foo May 05 '14 at 17:51
  • @larsmans The "safe" string functions are a different issue, since `` is also part of C++. And formally, at least, the "safe" string functions address a different issue: avoiding buffer overruns, rather than reentrance and thread safety. Whence the `_s` suffix, rather than `_r`. (But there is enough overlap that one would have liked to see them addressed together, with a common name.) – James Kanze May 06 '14 at 08:35
  • @JamesKanze I'll keep my opinion about the design of the `_s` functions to myself, but the POSIX functions I was referring to are actually `strdup`, `snprintf` (also C99) and `getline`. Those form an adequate guard against many buffer overruns, and they should have been in C99, but MS decided to reinvent the wheel. I don't really see the link to C++, because it's currently aligned with C99 and the `_s` functions are only in C11 (which MS doesn't even implement). – Fred Foo May 06 '14 at 10:44
  • @FredOverflow: it was actually spelled `extrn` in B. Like `creat`, and `/usr`, and other Unixisms. – Fred Foo May 06 '14 at 18:51
  • @FredFoo, MS VC 2015 actually has snprintf now (supposedly ISO 99 compliant) – Sebastian Apr 15 '16 at 07:21
35

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).

David Hammen
  • 30,597
  • 8
  • 54
  • 98
  • I'm not so sure about this. `auto a=1` seems harmless, but the more lint the language acquires, the harder it gets to understand code, and I'd be happier if GCC/CLang picked a sane subset of C11 to compile without `-fallow-old-cruft` (no trigraphs, automatic int, or `int f()` not being equivalent to `int f(void)`). – Fred Foo May 01 '14 at 21:56
  • @larsmans - Conceptually, what's the difference between `auto a;` and `register a`? You probably won't see many declarations of the form `auto a` in legacy code, but you sure are going to see a lot of declarations of the form `register a` in legacy code. I've seen `volatile register foo;` in legacy C code. Tell me how to make sense of that! – David Hammen May 01 '14 at 22:06
  • The difference is frequency, I guess, though I don't see that much `register a` either. I do still see K&R declarations with implicit `int` arguments, and I wish the compiler would simply refuse that cruft. – Fred Foo May 02 '14 at 07:20
  • 1
    @larsmans -- I can see where you're coming from. You want a `-ffs-please-stop-allowing-constructs-from-some-previous-millennium` compiler option, or more succinctly, a `-fstrict-compliance` option. Grumbling at the compiler: "When I used -std=c11 I did not expect that ancient K&R kruft to compile. In fact, I wanted it to **not** compile!" – David Hammen May 02 '14 at 11:50
  • 1
    Actually no, I want to have to turn *on* a flag to get the worst cruft to compile. But having `-std=c99` be stricter would be a step in the right direction :) – Fred Foo May 02 '14 at 12:12
  • 1
    If you use `gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror` (which is what I routinely use, even on code from questions on SO), then you get fairly close to what you want. I'd like GCC to default to at least `-std=c99` and preferably `-std=c11` (or, `-std=gnu11`; they'd more likely do that), but until then, … You can tweak those options; `-pedantic`, `-Wshadow`, `-Wold-style-declaration` and some others can be useful, but this is a good starting set of options. – Jonathan Leffler May 02 '14 at 14:18
  • I do like strict compilation flags, but I'm not a fan of `-Werror`. I instead like a rule that says "Compile with at least this set of flags: . Any warnings generated by the compiler must be explicitly approved in writing by the project manager and recorded in the waiver log. By the way, it's easier to get a waiver for a function with a cyclomatic complexity of 600 than it is to get a waiver for a compiler warning." – David Hammen May 02 '14 at 15:03
  • 3
    @DavidHammen: Neither cyclomatic complexity, project managers, nor company policies are elements of the language. – Jerry B May 03 '14 at 20:08
  • 3
    The flag to get the behavior you want in GCC is `-pedantic-errors` – τεκ May 03 '14 at 22:06
  • "In my opinion, this is what a decent compiler should do." Implicit int was removed from the language for a reason. Such code was bad long before C99. A good compiler does not let bad code compile. This answer is otherwise good, would have up-voted it if not for these opinions. – Lundin Aug 20 '18 at 06:54
29

auto has a meaning in C and C++ prior to the 2011 Standard. It means that a variable has automatic lifetime, that is, lifetime determined by the scope. This is opposed to, e.g., static lifetime, where a variable lasts "forever", regardless of the scope. auto is the default lifetime, and is almost never spelled out explicitly. This is why it was safe to change the meaning in C++.

Now in C, prior to the 99 Standard, if you don't specify the type of a variable, it defaults to int.

So with auto a = 1; you are declaring (and defining) an int variable, with lifetime determined by the scope.

("lifetime" is more properly called "storage duration", but I think that is perhaps less clear).

BoBTFish
  • 17,936
  • 3
  • 49
  • 73
  • Okay, so actually auto a=1 is allowed in C and means an int variable with automatic storage duration. – lee77 May 01 '14 at 10:59
  • 1
    Properly, "storage duration" takes one of a list of values, "automatic", "static", "dynamic", "thread". "Lifetime" is the actual time of life of the object. So the variable has storage duration "automatic" and lifetime "the duration of the scope of the `main` function". – Steve Jessop May 01 '14 at 10:59
  • @Steve yes, I didn't mean to imply that `auto` and `static` are the only two possibilities. I was trying to write my answer in a way targeted at the asker, who seems to be pretty new to `C++` (and `C`), so I glossed over the details a bit. Maybe that was a bad idea; they need to be covered sooner or later. – BoBTFish May 01 '14 at 11:04
  • 1
    @BoBTFish: oh, I wasn't complaining about that. I just meant to expand on the semantic difference between "lifetime", which is a duration, and "storage duration" which might more accurately have been called "storage duration category". – Steve Jessop May 01 '14 at 11:05
  • This implicit `int` stuff is removed from C since 1999. – Jens Gustedt May 01 '14 at 11:38
8

In C, and historic dialects of C++, auto is a keyword meaning that a has automatic storage. Since it can only be applied to local variables, which are automatic by default, no-one uses it; which is why C++ has now repurposed the keyword.

Historically, C has allowed variable declarations with no type specifier; the type defaults to int. So this declaration is equivalent to

int a=1;

I think this is deprecated (and possibly forbidden) in modern C; but some popular compilers default to C90 (which, I think, does allow it), and, annoyingly, only enable warnings if you specifically ask for them. Compiling with GCC and either specifying C99 with -std=c99, or enabling the warning with -Wall or -Wimplicit-int, gives a warning:

warning: type defaults to ‘int’ in declaration of ‘a’
Mike Seymour
  • 235,407
  • 25
  • 414
  • 617
5

In C, auto means the same thing register does in C++11: it means that a variable has automatic storage duration.

And in C prior to C99 (and Microsoft's compiler does not support either C99 or C11, although it may support parts of it), the type can be omitted in many cases, where it will default to int.

It does not take the type from the initialiser at all. You just happened to pick an initialiser that's compatible.

  • 1
    Isn't the register keyword deprecated in C++11? – sordid May 01 '14 at 10:57
  • @sordid Yes, it is. Prior to C++11, `auto` and `register` had the exact same meaning (I earlier commented that there were restrictions on taking a `register`-qualified variable's address, but that was incorrect for C++). `register`, while deprecated, retains its old meaning for now. –  May 01 '14 at 11:03
  • 5
    @JensGustedt: The answer doesn't say they are. It says that `auto` in C means the same as `register` in C++, which it does (both mean automatic storage duration, and nothing else). – Mike Seymour May 01 '14 at 11:52
3

Visual studio compilation type is available at right click on file -> Properties -> C/C++ -> Advanced -> Compile As. To make sure it is compiled as C force /TC option.Then in this case it is what larsmans said (old C auto keyword). It might be compiled as C++ without you knowing.

UmNyobe
  • 21,341
  • 8
  • 52
  • 85
3

A storage class defines the scope (visibility) and life time of variables and/or functions within a C Program.

There are following storage classes which can be used in a C Program

auto
register
static
extern

auto is the default storage class for all local variables.

{
        int Count;
        auto int Month;
}

The example above defines two variables with the same storage class. auto can only be used within functions, i.e. local variables.

int is default type for auto in below code:

auto Month;
/* Equals to */
int Month;

Below code is legal too:

/* Default-int */
main()
{
    reurn 0;
}
Amir Saniyan
  • 10,990
  • 18
  • 77
  • 124