Storage Class Specifiers
<no keyword>Visible to everything else in the regular scope. As a global, possibly other files; external definition - visible to other files - defines storage
staticVisible no other files.
externExternal reference - visible to other files - declares reference to an external defiintion somewhere
autoExists.
Example

An external definition

int a[10]; // external definition

An external reference; a reference to variable a from file1.c:

extern int a[10]; // external reference

If variable a was static, the extern in file2.c would fail.

Storage Keyword Combinations

Outside a function definitionInside a function definition
Nonescope: external definition
storage: static address
scope: within the function
storage: on the stack)
(same as auto)
autoN/Ascope: within the function
storage: on the stack
(same as None)
staticscope: within the file only
storage: static address
scope: external reference
storage: static address; location determined by file containing the external definition (can’t have intializer either)
registerN/Ascope: within the function
storage: register or stack (hint to compiler; use of & operator not allowed; seldom used)
Most important takeaways:
  • static has two meanings
    • inside a function: static changes the storage location to static memory (see C Memory Layout) instead of on the stack
    • outside a function: static changes the scope to be only visible with the file (the storage stays in static memory)
  • extern
    • Compiler does not allocate sotrage
    • For type check of the idenitifer name only
    • another C file must allocate storage by defining that varible or function
    • Typical way to link global variables between C files
  • volatile
    • tells the compiler not to optimize away the variable
    • use this for device registers
    • prevents compiler from optimizing (removing) dead code

Type Qualifiers

  • Can appear as part of the base type or within a declarator
  • Not mutally exclusive with a storage class
  • const - the value of this varibale is immutable after initialization
  • volatile - the compiler may not optimize reference to this variable (e.g. it’s a device register that may change value asynchronously)
  • restrict - for the lifetime of a pointer, only the pointer itsel or a value directly derived from it may be used to access the object to which it points. This allows better optimizzation but isn’t required.