kota's memex

Types can be qualified with one or more of the following: const, volatile, and restrict. Each of these qualifiers changes behaviors when accessing objects of the qualified type. Leaving these out you're left with "unqualified types". The qualified and unqualified versions of types can be used interchangably as arguments to functions, return values from functions, and members of unions.

const

Objects declared with the const qualifier are not modifiable. In particular, they're not assignable but can have constant initializers. This means objects with the const-qualified types can be placed in "read-only" memory by the compiler, and any attempt to write will result in a runtime error:

const int i = 1;
i = 2; // error: i is const-qualified

Both gcc and clang seems to pick this error up at build time!

C allows you to modify an object that is pointed to by a const pointer by casting the const away, provided that the original object was not also declared as const:

int i = 12;
const int j = 12;
const int *ip = &i;
const int *jp = &j;
*(int *)ip = 42; // ok
*(int *)jp = 42; // undefined behavior

volatile

Objects of volatile-qualified types server a special purpose. Static volatile-qualified objects are used to model memory mapped input/output (I/O) ports, and static constant volatile-qualified objects model memory-mapped input ports such as a real-time clock.

The values stored in these objects may change without the knowledge of the compiler. For example, every time the value from a read-time clock is read, it may change, even if the value has not been written to by the C program. Using a volatile-qualified type lets the compoler know that the value may change, and ensures that every access to the real-time clock that occures (otherwise, and access could be optimized away or replaces by a previously read and cached value.

In this example the compiler must generate instructions to read the value from port and then write it back to port:

volatile int port;
port = port;

Without the volatile qualifification, the compiler would see this as a no-op (operation that does nothing) and probably eliminate both the read and the write.

restrict

A restrict-qualified pointer is used to promote optimization. Objects indirectly accessed through a pointer frequently cannot be fully optimized because of potential aliasing, which occurs when more than one pointer refers to the same object. Aliasing can inhibit optimizations, because the compiler can't tell if portions of an object can change values when another apparently unrelated object is modified. So, it's only a good idea to use restrict if you're absolutely sure there will not be more than one pointer accessing your object.