32

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?

8
  • 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
    Commented Dec 14, 2020 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 Commented Dec 14, 2020 at 20:21
  • 28
    @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. Commented Dec 14, 2020 at 22:32
  • fair enough I never used auto in C code Commented Dec 14, 2020 at 22:39
  • 1
    Comments are not for extended discussion; the conversation about -> has been moved to chat.
    – wizzwizz4
    Commented Dec 15, 2020 at 11:59

3 Answers 3

44

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.

6
  • 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? Commented Dec 14, 2020 at 19:16
  • 2
    @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
    Commented Dec 14, 2020 at 19:37
  • From what I understand =op was possible on very early C as well. Commented Dec 14, 2020 at 21:56
  • 3
    But why is B's choice of the asterisk as the escape character a "glaring problem"? Commented Dec 14, 2020 at 21:57
  • 5
    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. Commented Dec 15, 2020 at 16:58
16

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;
    switch(count%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++;
        }while(--n>0);
    }
}

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.

0
5

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.

5
  • 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
    Commented Dec 15, 2020 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. Commented Dec 16, 2020 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
    Commented Dec 17, 2020 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.) Commented Dec 17, 2020 at 18:42
  • @Ray Ah yes I missed that, makes sense..
    – Voo
    Commented Dec 17, 2020 at 19:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .