Intro

From the K&R book:

For most programmers, the most important change is a new syntax for declaring and defining functions. A function declaration can now include a description of the arguments of the function; the definition syntax changes to match. This extra information makes it much easier for compilers to detect errors caused by mismatched arguments; in our experience, it is a very useful addition to the language. (p. 2)

C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly. (p. 3)

Variables

Static

Enums

enum months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };

const

const int a = 2;
int *pa = &a; // this will make const on line 1 useless

const int *pa = &a;
*pa = 9; // can't assign

int *const pa = &a;
pa = &a; // can't change what it points to

Bitwise

Operators

Bitwise operators    
& AND  
| OR  
^ XOR  
<< left shift a << x is the same as a * 2^x
>> right shift a >> x is the same as a / 2^x
~ 1’s complement It will be represented as a negative number.

Examples

a & ~8 // turn fourth bit off
a | 8 // turn fourth bit on
a ^ 8 // flip the fourth bit
int a = 5, b;
b = a++; // this will set b to 5 and a to 6
b = ++a; // this will set b to 6 and a to 6

Bit-fields

enum
{
    KEYWORD = 01,
    EXTERNAL = 02,
    STATIC = 04
};

// turn on EXTERNAL and STATIC bits in flags
flags |= EXTERNAL | STATIC
// turn off
flags &= ~(EXTERNAL | STATIC);
// test them
if ((flags & (EXTERNAL | STATIC)) == 0)

Using a struct bit-field

    struct
    {
        unsigned int is_keyword : 1;
        unsigned int is_extern : 1;
        unsigned int is_static : 1;
    } flags;

    flags.is_extern = flags.is_static = 1;
    flags.is_extern = flags.is_static = 0;
    if (flags.is_extern == 0 && flags.is_static == 0)

Fields may be declared only as ints, specify unsigned explicitly.

Unions

Union is a variable that may hold objects of different types and sizes.

union u_tag {
    int ival;
    float fval;
    char *sval;
} u;

u.ival;

See: SO: Why do we need C Unions?

Accessing individual bytes

typedef union
{
    struct {
        unsigned char byte1;
        unsigned char byte2;
        unsigned char byte3;
        unsigned char byte4;
    } bytes;
    unsigned int dword;
} HW_Register;
HW_Register reg;

reg.dword = 0x12345678;
// reg.bytes.byte3 will be 56 (depends on endianess)

Accessing individual bits of a byte

typedef union
{
    struct {
        unsigned char b1:1;
        unsigned char b2:1;
        unsigned char b3:1;
        unsigned char b4:1;
        unsigned char reserved:4;
    } bits;
    unsigned char byte;
} HW_RegisterB;
HW_RegisterB reg;

reg.byte = 15;
// reg.bits.b3 will be 1

Function pointers

int fun(int a) {
    return a * 2;
}

int (*fun_ptr)(int) = &fun; // & is optional
(*fun_ptr)(10); // * is optional, fun_ptr(10) also works
void wrapper(void (*fun)(int)) // * is optional, fun(int) also works
{
    fun(2);
}

References