Variables#

A variable in C names a typed slot. Type, storage class, and scope are explicit; the compiler infers nothing. Storage classes (auto, register, static, extern) control lifetime and linkage; scope is determined by where the declaration appears (block, function, file, program).

/types`.

Declaration#

A declaration is T name; (with optional initialiser). A declaration that allocates storage is a definition.

int    n;                   /* uninitialised; value is indeterminate */
int    m = 0;               /* defined and initialised */
const  int  PI3 = 3;        /* read-only */
char   buf[256];            /* array */
char  *p;                   /* pointer */
struct user u;              /* struct instance */

Globals (file-scope) and static locals are zero-initialised; block-scope locals are not, and reading one before assignment is undefined behaviour.

Storage classes#

Specifier

Effect

auto

default for block-scope locals. Lifetime ends when the enclosing block exits.

register

hint to keep in a register. Modern compilers ignore; &x becomes illegal.

static (at block scope)

one slot per program lifetime; preserved across calls.

static (at file scope)

internal linkage; not visible to other translation units.

extern

declaration without definition; lives in another translation unit and the linker resolves it.

_Thread_local / thread_local (C11+)

per-thread storage; one slot per thread.

/* file scope */
static int  cache_size = 0;       /* private to this .c file */
extern int  global_counter;       /* defined elsewhere */

void hit(void) {
    static int call_count = 0;    /* persists across calls */
    call_count++;
    printf("%d\n", call_count);
}

Scope#

Scopes in C: block (inside {...}), function (only labels), file (the rest of the translation unit), and function prototype (only inside a prototype’s parameter list).

int main(void) {
    int x = 1;
    {
        int x = 2;             /* shadows the outer x */
        printf("%d\n", x);     /* 2 */
    }
    printf("%d\n", x);         /* 1 */
    return 0;
}

Avoid shadowing intentionally; -Wshadow catches it.

Type qualifiers#

Qualifier

Meaning

const

object cannot be modified through this name. const char *p is a pointer to const; char *const p is a const pointer.

volatile

the compiler may not optimise reads / writes away. Required for MMIO and sig_atomic_t variables.

restrict

this pointer is the only access path to the object through this function. Lets the compiler optimise.

const char *msg = "ok";                  /* msg can move; *msg cannot */
char *const HEAD = buf;                  /* HEAD fixed to buf; *HEAD mutable */
volatile uint32_t *reg = (uint32_t*)0xDEADBEEF;

void memcpy_fast(void *restrict dst, const void *restrict src, size_t n);

typedef#

typedef creates an alias for an existing type. The operator uses it to name struct-as-tag types (http_client_t) and to abstract platform widths.

typedef unsigned long long u64;
typedef struct http_client http_client_t;

u64 counter = 0;
http_client_t *c = http_client_new();

Initialisation#

Compound literals and designated initialisers (C99+) let the operator build structs and arrays inline.

struct config {
    const char *host;
    int port;
};

struct config c = {.host = "0.0.0.0", .port = 80};
struct config defaults[] = {
    {.host = "a", .port = 1},
    {.host = "b", .port = 2},
};

int xs[10] = {[5] = 42};     /* zero elsewhere, 42 at index 5 */

A zero initialiser for an aggregate fills every field with the zero of its type.

struct user u = {0};          /* every field zeroed */
char buf[256] = {0};          /* every byte zeroed */

Lifetime#

  • Automatic (block-scope auto / default): lives from block entry to exit. Stored on the stack.

  • Static (static, file-scope, extern): lives the whole program. Stored in BSS / data segment.

  • Allocated (malloc / calloc / realloc): lives until free. Stored on the heap.

  • Thread-local (_Thread_local): one slot per thread, lives the thread’s lifetime.

References#

  • Syntax for the lexical rules int, static, extern parse against.

  • Types for the type system the declarations name.

  • Functions for parameter scope and register semantics inside calls.

  • Runtime for the BSS / data / stack / heap memory model.

  • C17 standard, Declarations.