Skip to content

Summary of C

Types

  • statically-typed
    • The type of every expression (except those involving VLAs) is known at compile-time

Arithemetic types

  • 1==sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
  • sizeof(signed T)==sizeof(unsigned T) for every \(T \in\{\) char, short, int, long, long long }
  • short and int are at least 16 bits. long is at least 32 bits. long long is at least 64 bits.
  • Range of signed types: \(\left[-2^{N-1}, 2^{N-1}-1\right]\). Range of unsigned types: \(\left[0,2^N-1\right]\)
  • Whether char is signed or not is implementation-defined.
  • Signed integer overflow is undefined behavior.
  • Unsigned arithmetic never overflows: It is performed modulo \(2^N\), where \(N\) is the number of bits of that type.

Pointer types

PointeeType *

  • For T!=U, T * and U * are different types.
  • The value of a pointer of type T * is the address of an object of type T.
  • Null pointer: The pointer holding the null pointer value, which is a special value indicating that the pointer is "pointing nowhere".
    • A null pointer can be obtained from NULL .
  • &var returns the address of var. The return type is pointer to the type of var .
  • Only when a pointer is actually pointing to an object is it dereferenceable.
  • *ptr, where ptr is not dereferenceable, is undefined behavior.

Array types

ElemType [N]

  • Different Types
  • N should be compile-time constant. Otherwise it is a VLA.
  • Valid index range: \([0, N)\). Subscript out of range is undefined behavior.
  • Decay: a -> &a[0] , T[N] -> T *

Pointer to array: T (*)[N] . Array of pointers: T *[N] .

struct

A special data type consisting of a sequence of members.

  • The type name is struct StructName .
  • sizeof (struct X) \(\geqslant \sum_{\text {member } \in X}\) sizeof (member)

Variables

  • Declare: Type varName
    • Array: ElemType varName[N]
    • Pointer to Array: T (*varName)[N]
  • Initialize: = initializer
    • Brace-enclosed list initializer for arrays and structs: = { ... }
      • Designators for arrays: = {[3] = 5, [7] = 4}
      • Designators for structs: = {.mem1 = x, .mem2 = y} .

Initialization

Variable declared without explicit initializer

  • For global or local static variables, they are empty-initialized:
    • 0 for integer types,
    • +0.0 for floating-point types,
    • null pointer value for pointer types.
  • For local non-static variables, they are uninitialized, holding indeterminate values

These rules apply recursively to the elements of arrays and the members of structs. Any use of the value of an uninitialized variable is undefined behavior

Scopes and name lookup

Expressions

  • Operator precedence, associativity, and evaluation order of operands
  • The only four operators whose operands have deterministic evaluation order:
    • && and || : short-circuit evaluation
    • ?:
    • , (not in a function call or in an initializer list)
  • If the evaluation order of A and B is unspecified, and if
    • both A and B contain a write to an object, or
    • one of them contains a write to an object, and the other one contains a read to that object
  • then the behavior is undefined.

Arithmetic operators

  • +, -, *, /, %
    • Division: Truncated -> 0
    • (a / b) * b + (a % b) == a
    • For + , - , * and / , the operands undergo a series of type conversions to a common type.
  • Bitwise
    • ~, &, |, ^, <<, >>
  • Compound a op= b <=> a = a op b
  • In/Decrease
  • Be careful with signed overflows

Pointer arithmetic

  • Pointer arithmetic: Plus(Increase), Minus(Decrease)
  • Pointer arithmetic uses the units of the pointed-to type.
    • p + i == (char *)p + i * sizeof(*p)

Function

Pointer to function

void f();

// void *p = f
void (*pf)(void) = f;
// f() == pf();