The auto keyword in C seems quite redundant: wherever it makes sense to define a variable with automatic storage duration, it is already the default, so there is no reason to use the keyword. The keyword is so useless that C++11 managed to repurpose it for type deduction, with impunity: the change made virtually no impact on syntax-compatibility with C code.

We do know, however, that some seemingly superfluous syntactical features of C, like the register keyword (made mostly obsolete by modern register allocators) and the -> operator, did serve some purpose historically, even if they are mostly redundant now. I would assume the same is the case with auto.

Why was the auto storage class specifier added to C? Was it inherited from another language? Included ‘for completeness’? Is there a document that provides a rationale for its existence?

  • 2
    When processing code which the gcc optimizer cannot be trusted to process meaningfully, the register storage qualifier can offer a huge performance boost, sometimes allowing loops to execute just as fast in -O0 mode as they would with optimizations enabled. – supercat Dec 14 '20 at 18:28
  • 8
    "The keyword is so useless that C++11 managed to repurpose it for type deduction" C++ is not C. A C code is not necessarily a valid C++ code – Jean-François Fabre Dec 14 '20 at 20:21
  • 27
    @Jean-FrançoisFabre: C++ is not C, but it maintains syntax compatibility with C to a large extent. The fact that repurposing the auto keyword had so little impact on that is quite remarkable. – user3840170 Dec 14 '20 at 22:32
  • fair enough I never used auto in C code – Jean-François Fabre Dec 14 '20 at 22:39
  • 1
    Comments are not for extended discussion; the conversation about -> has been moved to chat. – wizzwizz4 Dec 15 '20 at 11:59

It wasn't added in C; it was inherited from B. The B Programming Language didn't have types, so there no way to declare a variable local to function without using the auto keyword.

So, for example, you might have a B function something like:

add(a, b) {
    auto ret;
    ret = a + b;
    return ret;

Because of the default int rule in C, that's also a valid C program, and it is equivalent to this modern "ANSI C" version:

int add(int a, int b) {
    int ret;
    ret = a + b;
    return ret;

I'm not sure there was any rationale for including the auto keyword in C other than it allowed most existing B programs to be valid C programs.

  • I realised it came from B soon after posting the question. Still I wonder, was it common to declare variables with auto in C? Was it an actual consideration to be syntax-compatible with B? Or was the compatibility there because B evolved into C, and nobody bothered to remove the keyword? – user3840170 Dec 14 '20 at 19:16
  • 1
    @user3840170 I'm pretty sure it was a deliberate decision to be compatible with B. If that compatibility wasn't a goal Dennis Ritchie would've probably made bigger changes and fewer B programs would have been valid C programs, even today. The incompatible changes C did make were for more glaring problems with B, like changing the character escape character from an asterisk to a backslash (eg. '*n' to '\n', and changing compound assignment operators to be of the form op= instead of =op. That last change also got picked up by more modern versions of B. – user722 Dec 14 '20 at 19:37
  • From what I understand =op was possible on very early C as well. – OmarL Dec 14 '20 at 21:56
  • 3
    But why is B's choice of the asterisk as the escape character a "glaring problem"? – OmarL Dec 14 '20 at 21:57
  • 4
    The =op to op= change certainly makes far more sense, consider the line x=-2; vs x= -2; In C (and most C-like languages) these are identical. In B, that space makes the difference between subtracting 2 from x and setting x to -2, completely different. – Darrel Hoffman Dec 15 '20 at 16:58

The keyword was inherited from B.

B was a programming language with no type system at all: every variable held a machine word (corresponding to the int type in C), and the type of each value was determined by the operation performed. Since there was no type to specify for variables, the only thing to declare about a variable was its storage class; unlike in C, the default in B corresponded to C’s static, i.e. a variable that existed for the duration of the whole program’s run time. Thus the auto keyword was included to denote automatic variables, which existed only for the duration of a single function call. The term automatic itself came from PL/I, from which B also borrowed the /* ... */ comment syntax.

While C added type declarations, int was kept as the implicit default, and it was still possible to declare int variables with only the storage class specifier, just like in B. In the early days of C, it was common to rely on this. Here’s for example the famous Duff’s device from 1983:

send(to, from, count)
register short *to, *from;
register count;
    register n=(count+7)/8;
    case 0: do{ *to = *from++;
    case 7:     *to = *from++;
    case 6:     *to = *from++;
    case 5:     *to = *from++;
    case 4:     *to = *from++;
    case 3:     *to = *from++;
    case 2:     *to = *from++;
    case 1:     *to = *from++;

Duff omits any type specifiers for the count parameter, the n variable and the return type of send; all are assumed to be int. (Since he doesn’t actually return any value from the function, he would have probably used void for the return type in modern C, but that barely existed back then.) The K&R-style declaration for function parameters he uses for the send function is also a straightforward extension of B syntax.

We can therefore surmise that the auto keyword was included ‘for symmetry’ with other storage class specifiers, to support this coding style that relied on implicit int; this also eased porting B code into C. Whether compatibility with B code was an explicit goal or just an emergent property coming from the fact that the first C compiler grew out of a B compiler, I don’t know. But it was probably a consideration.

Over the years, implicit int fell into disuse (with contemporary compilers emitting warnings against it), and with it, the auto keyword as well. (I’d assume auto was never popular in C in the first place, as int is one character shorter, so everyone declared the type anyway.) With the B language extinct, and B-derived K&R C displaced by ISO C, the keyword became redundant.


Minority report:

user3840170 answered:

I’d assume auto was never popular in C in the first place, as int is one character shorter, so everyone declared the type anyway.

Some of us more anal retentive types always used "auto":

auto int x;
auto int y;

as two lines, never as:

int x, y;

It made it much easier to find all the declarations by simply searching for "auto".

Or perhaps it was over-reaction to finding:

char*  x,y;

wasting time wondering if that's what they really meant, and having to rewrite it as:

auto char *x;
auto char  y;

if it actually was correct.

Things like:

char *x, *rindex(), *y;

where implicit "auto" and "extern" were combined, were annoying too.

Asking "Why is the ‘auto’ storage class specifier included in C?" is the wrong question.
It should be "Why wasn't the 'auto' storage class specifier required in C?".
To me it makes even less sense than leaving the "e" off "creat()".

Note: this answer was inspired by a similar frustration (about making things more complicated by simplifying them) that I just commented in Chinese.SE Is pinyin an accurate pronunciation guide?:

@goPlayerJuggler says "once you understand its (sometimes quite counter-intuitive) rules". Ironically (to an outsider at least), those complicating rules were done in the name of simplification. E.g. When a "ü" is used where a "u" would be illegal, then omit the umlaut — The sequence "ui" is never legal, so omit the "e" from sequence "uei".

Which is why "Feng shuei" is spelled "Feng shui", and commonly mispronounced as a result.

  • 3
    I just put one declaration per line without using the auto keyword. It wasn't too hard to find them since they'd be at the start of the function. – user722 Dec 15 '20 at 20:25
  • In a well factored program, finding declarations is not hard. It's when you start doing 10-page functions, that leave side effects and horribleness that it's hard. I agree pinyin is nutso though. – OmarL Dec 16 '20 at 9:00
  • As someone who didn't write any C in the 80s I don't understand the first examples. I can understand why you wouldn't want int a,b; (and particularly not the pointer examples!) but not why you'd need auto for the counter example instead of simply int a; int b;. – Voo Dec 17 '20 at 18:25
  • 3
    @Voo, g/auto/p would list all the declarations. (For context, consider that in the early 80s, my terminal's modem had a light that indicated "HS" for when it was able to make a High Speed connection, 1200 baud as opposed to 300 baud. That's .0012 Mb/s.) – Ray Butterworth Dec 17 '20 at 18:42
  • @Ray Ah yes I missed that, makes sense.. – Voo Dec 17 '20 at 19:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.