Why does auto a=1; compile in C?
Asked Answered
F

7

129

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?

Fuzzy answered 1/5, 2014 at 10:50 Comment(10)
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.Edsel
The code gets compiled without errors by the MS Visual Studio 2012 compiler - what happens when you enable warnings?Segal
@JensGustedt MSVC++ only supports C89 (and a few features from C99). It's more of a C++ compiler.Honaker
@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...Fuzzy
@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.Besetting
@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.Edsel
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.Deedeeann
This was asked in reddit reddit.com/r/programming/comments/24mvym/… , #justsaying.Kendrick
Thankfully MS have more recently changed their mind and said they will support C99. Took 'em long enough though...Aftermost
@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.Marianmariana
A
241

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.

Asha answered 1/5, 2014 at 10:50 Comment(25)
No, this isn't legal C since 1999. No decent modern C compiler allows for this.Edsel
@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.)Marianmariana
And of course, B didn't run only on PDP-11, since it was developed before the PDP-11 existed.Marianmariana
@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.Edsel
@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.Asha
@JamesKanze: I stand corrected about the platforms supported by B.Asha
I think the new gcc4.9 has an auto keyword which is identical to c++.Gerdy
@self The changelog says it's called __auto_type.Asha
That is what I was referring to.Gerdy
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;Fyn
@Zack a; was never a declaration, but a statement.Asha
@larsmans In the original K&R C, a; was a declaration, at least at file scope.Marianmariana
@Zack auto a is neither valid in C99 nor C11.Edsel
@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 ...Edsel
@JensGustedt: amended the answer.Asha
@JensGustedt MSVC supports only C89.Chemnitz
@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.Mccallister
@Jens A compiler is free to accept an otherwise incorrect program. Behavior is implementation defined in this case.Lamina
@JamesKanze "VS doesn't claim to provide a modern C compiler" Neither a modern C++ compiler, I think...Larrigan
@Larrigan 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.Marianmariana
@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.Asha
@larsmans The "safe" string functions are a different issue, since <cstring> 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.)Marianmariana
@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).Asha
@FredOverflow: it was actually spelled extrn in B. Like creat, and /usr, and other Unixisms.Asha
@FredFoo, MS VC 2015 actually has snprintf now (supposedly ISO 99 compliant)Otolaryngology
M
36

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

Mccallister answered 1/5, 2014 at 14:3 Comment(10)
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)).Asha
@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!Mccallister
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.Asha
@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!"Mccallister
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 :)Asha
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.Tiresias
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: <elided>. 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."Mccallister
@DavidHammen: Neither cyclomatic complexity, project managers, nor company policies are elements of the language.Hypocorism
The flag to get the behavior you want in GCC is -pedantic-errorsFroward
"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.Crist
P
30

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

Phoebephoebus answered 1/5, 2014 at 10:54 Comment(5)
Okay, so actually auto a=1 is allowed in C and means an int variable with automatic storage duration.Fuzzy
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".Strongbox
@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.Phoebephoebus
@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".Strongbox
This implicit int stuff is removed from C since 1999.Edsel
T
9

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’
Teenybopper answered 1/5, 2014 at 10:58 Comment(1)
It is indeed forbidden in C since 1999.Edsel
U
6

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.

Upi answered 1/5, 2014 at 10:54 Comment(3)
Isn't the register keyword deprecated in C++11?Lubet
@Lubet 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.Upi
@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).Teenybopper
L
4

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.

Lib answered 1/5, 2014 at 10:57 Comment(0)
A
4

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;
}
Abrahamabrahams answered 7/5, 2014 at 16:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.