=head1 Why consting is good

In Perl, we have the C<use constant> pragma to define unchanging
values.  The L<Readonly> module extends this to allow arrays and
hashes to be non-modifiable as well.

In C, we have C<const> numbers and pointers, and using them wherever
possible lets us put safety checks in our code, and the compiler
will watch over our shoulders.

=head2 C<const> numbers

The easiest way to use the C<const> qualifier is by flagging numbers
that are set at the top of a block.  For example:

    int max_elements;

    max_elements = nusers * ELEMENTS_PER_USER;

    ...

    array[max_elements++] = n;
    /* but you really meant array[max_elements] = n++; */

Adding a C<const> qualifier means you can't accidentally modify
C<max_elements>.

    const int max_elements = nusers * ELEMENTS_PER_USER;

=head2 C<const> pointers

If a pointer is qualified as const, then its contents cannot be
modified.  This lets the compiler protect you from doing naughty
things to yourself.

Here are two examples for functions you're familiar with:

    int strlen( const char *str );
    void memset( char *ptr, char value, int length );

In the case of C<strlen>, the caller is guaranteed that any string
passed in won't be modified.  How terrible it would be if it was
possible for C<strlen> to modify what gets passed in!

The const on C<strlen>'s parameter also lets the compiler know that
C<strlen> can't be initializing what's passed in.  For example:

    char buffer[ MAX_LEN ];

    int n = strlen( buffer );

The compiler knows that C<buffer> hasn't been initialized, and
that C<strlen> can't be initializing it, so the call to C<strlen>
is on an uninitialized value.

Without the const, the compiler assumes that the contents of any
pointer are getting initialized or modified.

=head2 C<const> arrays

Consting arrays makes all the values in the array non-modifiable.

    const int days_per_month[] =
        { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

You don't want to be able to do C<days_per_month[1] = 4;>, right?
(We'll ignore that about 25% of the time you want C<days_per_month[1]>
to be 29.)

=head2 Mixing C<consts>

Combining C<const>s on a pointer and its contents can get confusing.
It's important to know on which side of the asterisk that the
C<const> lies.

To the left of the asterisk, the characters are constant.  To the
right of the asterisk, the pointer is constant.

Note the difference between a pointer to constant characters:

    /* Pointer to constant characters */
    const char *str = "Don't change me.";
    str++;      /* legal, now points at "o" */
    *str = "x"; /* not legal */

and a constant pointer to characters:

    /* Constant pointer to characters */
    char * const str = buffer;
    str++;      /* not legal */
    *str = 'x'; /* buffer[0] is now 'x' */

Note the difference between which side of the asterisk that the
C<const> is on.

You can also combine the two, with a constant pointer to constant
characters:

    const char * const str = "Don't change me";

or even an array of constant pointers to constant characters:

    const char * const days[] =
        { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

If you see a declaration you don't understand, use C<cdecl>.  It's
standard in many C compiler suites, and is freely available around
the net.

    $ cdecl
    Type `help' or `?' for help
    cdecl> explain const char * str;
    declare str as pointer to const char
    cdecl> explain char * const str;
    declare str as const pointer to char
