This helpful cheatsheet was archived on the wayback machine. I wanted to post a formatted copy up on my site for posterity. Original author: *PMK 10-16-2002*.

Every constant, object, function, and expression in C has a type. Most generally, a type is either an unqualified type or such a type qualified with *const*, *volatile*, or both qualifiers. Unqualified types comprise three categories:

```
Object types
Scalar
Arithmetic
Integral
signed/unsigned/plain
character types
short, int, long
bitfield
enumeration
Floating-point
Pointer to general type
Aggregate
struct/union of object types and bitfields
known-size array of objects
Incomplete types
void
undefined struct/union
array of unknown size of objects
array of incomplete type (except void)
Function returning void or unqualified object type (except array)
(with no arguments, with unknown or old-style arguments, or
with prototyped arguments of general types)
```

*Bitfields* may appear only as struct/union members, so there are no pointers to bitfields, arrays of bitfields, or functions taking or returning bitfields.

Some types are silently replaced. A qualified array type becomes an unqualified array of the qualified type, and function arguments that are arrays or functions become pointers.

*Binding* is just like expressions: postfix before prefix. So parentheses are necessary in declarators only for function arguments and for pointers to functions and arrays!

In

qualifiedpointer types, the pointer qualifiers appear after the *.

How to easily read a declaration from left to right:

```
transform function argument types from inside out first
move the base type to the end
add outer parentheses if there's an initial *
change every (*...) to ... ->
one -> for each *
move qualifiers, so * const becomes const ->
```

Example: const int *(**const x [])()

```
*(**const x [])() const int base type to end
(*(**const x [])()) const int add outer parens
(**const x [])() -> const int remove outer ()
x [] const -> -> () -> const int remove inner ()
array of constant pointers to pointers to functions
returning pointers to constant ints
```

Constants are **double** unless suffixed by *F* or *L*.

Take the first type that fits in one of these lists:

```
*with 'U'*: unsigned int, unsigned long
*with 'L'*: long, unsigned long
*with 'UL'*: unsigned long
*decimal*: int, long, unsigned long
*octal, hex*: int, unsigned int, long, unsigned long
```

So 2147483648 is long but 0x80000000-0xffffffff are unsigned int.

Are *“int”*.
String literals are arrays of *char*.

Any *zero-valued* integral constant expression, possibly cast to (void *).

These are the classes of operators in **decreasing order** of precedence.

```
(x)
postfix: x[y], x(...), x.y, x->y, x++, x--
prefix: ++x, --x, (type) x, sizeof x, &x, *x, +x, -x, ~x, !x
multiplicative: x*y, x/y, x%y
additive: x+y, x-y
shift: x<<y, x>>y
relational: x<y, x<=y, x>y, x>=y
equality: x==y, x!=y
bitwise AND: x&y
bitwise XOR: x^y
bitwise OR: x|y
logical AND: x&&y
logical OR: x||y
conditional: x?y:z
assignment: x=y and *= /= %= += -= <<= >>= &= ^= |=
sequence: x,y
```

All binary operators are left-associative where it makes a difference, except of course for assignment. The conditional operator (x?y:z) is the *only* doubtful case that is right-associative!

```
So x ? y : a ? b : c
is x ? y : (a ? b : c)
not (x ? y : a) ? b : c
```

```
x->y means (*x).y
x[y] means *(x+y)
!x means x == 0
```

Rules applying to x.y and *x may thus apply to x->y or x[y] as well.

Note that “!!x” is equivalent to “x != 0”.

Pointer arithmetic is always in units of the pointer’s base type. This means that adding or subtracting an integer to or from a pointer yields a pointer to another element in the same array.

```
p + 1 == &p [1]
```

Subtracting two pointers yields a distance that is also in units of the pointer’s base type.

These operators always return either 0 or 1:

```
!x
relations and equalities (<, <=, >, >=, ==, !=)
x && y
x || y
```

The logical operators (x && y, x || y) do not evaluate their second operands if the first operand determines the result.

```
-x == ~x + 1
~x == -1 - x
x & -(1<<y) lowers x to a multiple of a power of two
(1 << x) - y == y ^ ((1 << x) - 1)
(x&y) + (x|y) == x + y == (x^y) + ((x&y) << 1)
```

Note that

sizeof (type)requires parenthese, whilesizeof expressiondoes not.

An **Lvalue** represents the location of an object or function, and might be the target of assignment. An **Rvalue** is any other value, such as an object’s value or a constant or a function result.

Only these expressions are Lvalues:

```
identifiers of objects and functions
"string literal"
(Lvalue)
Lvalue.member
*Rvalue
```

*x.y* is an Lvalue if *x* is, and has all the qualifiers of the types of both *x* and *y*. Casts are not Lvalues. As a consequence of the syntactic equivalences noted above, these expressions are also Lvalues:

```
Rvalue->member
Rvalue [Rvalue]
```

```
function
array
incomplete
const-qualified
struct/union with any unmodifiable member
```

Lvalues (other than arrays and functions) become Rvalues of unqualified type **except** in these contexts:

```
sizeof
&x
x++, x--, ++x, --x
x.member
left sides of assignments (x=..., x+=..., etc.)
```

Lvalues of array type are converted to Rvalues of pointer type pointing to their first members **except** in these contexts:

```
sizeof
&x
"string literal" in a character array initializer
```

There are no Rvalues of array type in C outside

sizeof.

Function designators are converted to Rvalues of pointer to function type (except in *&x* which does that anyway). So if *f* is the name of a function, all of these are synonyms, and all have type *“pointer to function”*:

```
f
*f
***f
************************************f
```

Rvalues of these types (plain, signed, and unsigned) become type *int* or *unsigned int*:

```
char
short
bitfields of type int or smaller
enum
```

Given two operands to a binary operator, find the first type in this list that matches one of the operands, then convert the other operand to that type.

```
long double
double
float
(apply integral promotion, then)
unsigned long
long + unsigned -> long or unsigned long
long
unsigned
int
```

```
integral promotions
float -> double
```

There is an implicit “x != 0” in

```
if (x)
while (x)
do while (x)
for (; x; )
x && x
x || x
x ? y : z
```

An explicit “x != 0” in these contexts serves no semantic purpose. And “x == 0” in these contexts might be better written as “!x”.

```
file
block
entire function body (for labels)
prototype
```

Beware struct/union/enum tags in prototype scopes!

Distinct namespaces (*per scope*):

```
struct/union/enum tags
labels
everything else
```

Storage classes determine linkage of names thus:

```
if "static" {
if file scope
linkage is internal
else
no linkage
} else if "extern" or a function {
if a declaration is visible at file scope
link to it
else
linkage is external
} else if file scope
linkage is external
else
no linkage
```

Object declarations with initializers and function declarations with bodies are definitions. Object declarations without initializers are tentative definitions with zero fill if they are not **extern**.

A C compiler must behave as if each of these steps were completely performed before proceeding.

- Turn end-of-line indicators into newlines and replace ??trigraphs
- Delete all backslash-newline pairs
- Form tokens and replace comments by single spaces
- Preprocessing and macro expansion
- Process \escape sequences in ‘character constants’ and “string literals”
- Delete white space, including newlines
- Concatenate adjacent “string literals”
- Parse and generate code
- Link

Hope others find this helpfule just as I have!