Search code examples
cstorage-class-specifier

Does every variable have a storage class in C?


Naively one could think it has, because usually auto is assumed when a storage class keyword is not supplied.

Still, for file-scoped variables putting an auto in front of them gives an error.

#include <stdio.h>

auto int x;

int main(void){
  x = 7;
  printf("x = %d", x);
}

Clang complains:

3:10: error: illegal storage class on file-scoped variable
auto int x;

Declaring x without any storage class keyword and it compiles:

#include <stdio.h>

int x;

int main(void){
  x = 7;
  printf("x = %d", x);
}

Now I wonder what storage class x has in the example above? Does it have a name?


Solution

  • The keywords auto, static, extern, register, and _Thread_local are referred to in the standard as storage class specifiers, but "objects" (this is the standardese term for what we usually call "variables") don't have storage classes. Instead they have linkage (external, internal, none) and storage duration (static, automatic, thread). In addition, any declaration of an object may or may not be a definition. The storage class specifiers, together with the scope at which the object is declared, and whether or not it has an initializer (int foo vs int foo = 3), control these properties. It's easiest to show how this works with a table:

    sc-specifier scope initialized   linkage    storage duration    is a definition
    ------------ ----- -----------   -------    ----------------    ---------------
    auto         file  no            [constraint violation]
    auto         file  yes           [constraint violation]
    auto         block no            none       automatic           yes
    auto         block yes           none       automatic           yes
    
    none         file  no            external   static              yes
    none         file  yes           external   static              yes
    none         block no            none       automatic           yes
    none         block yes           none       automatic           yes
    
    static       file  no            internal   static              yes
    static       file  yes           internal   static              yes
    static       block no            none       static              yes
    static       block yes           none       static              yes
    
    extern       file  no            external   static              no
    extern       file  yes           external   static              yes
    extern       block no            external   static              no
    extern       block yes           external   static              yes
    

    The term "storage class specifier" is intentionally different from the terms "storage duration" and "linkage" to remind you that the specifiers don't give you independent control over the storage duration and linkage.

    The language doesn't give you independent control over storage duration, linkage, and being a definition because the combinations that are unavailable don't make sense. Automatic storage duration only makes sense for variables declared at block scope, not being a definition only makes sense for variables with external linkage (because only they could be defined in another file), and so on.

    I left register and _Thread_local out of the table because they are special. register is just like auto except that it also means you're not allowed to take the address of the object. _Thread_local makes the storage duration of the variable be "thread" and doesn't change the linkage; it can be used by itself or with extern or static, but it's a constraint violation to combine it with "auto". I'm not sure what it does if you use it at block scope by itself.