Q:

What is data alignment? Why and when should I be worried when typecasting pointers in C?

I couldn't find a decent document that explains how the alignment system works and why some types are more strictly aligned than the others.

A:

I'll try to explain in short.
What is data alignment?
The architecture in you computer is composed of processor and memory.
Memory is organized in cells, so:
 0x00 |   data  |  
 0x01 |   ...   |
 0x02 |   ...   |

Each memory cell has a specified size, amount of bits it can store. This is architecture dependent.
When you define a variable in your C/C++ program, one or more different cells are occupied by your program.
For example
int variable = 12;

Suppose each cell contains 32 bits and the int type size is 32 bits, then in somewhere in your memory:
variable: | 0 0 0 c |  // c is hexadecimal of 12.

When your CPU has to operate on that variable it needs to bring it inside its register. A CPU can take in "1 clock" a small amount of bit from the memory, that size is usually called WORD. This dimension is architecture dependent as well.
Now suppose you have a variable which is stored, because of some offset, in two cells.
For example I have two different pieces data to store (I'm going to use a "string representation to make more clear"):
data1: "ab"
data2: "cdef"

So the memory will be composed in that way (2 different cells):
|a b c d|     |e f 0 0|

That is, data1 occupies just half of the cell, so data2 occupies the remaining part and a part of a second cell.
Now suppose you CPU wants to read data2. The CPU needs 2 clocks in order to access the data, because within one clock it reads the first cell and within the other clock it reads the remaining part in the second cell.
If we align data2 in accordance with this memory-example, we can
introduce a sort of padding and shift data2 all in the second cell.
|a b 0 0|     |c d e f|
     ---
   padding

In that way the CPU will lose only "1 clock" in order to access to data2.
What an align system does
An align system just introduces that padding in order to align the data with the memory of the system, remember in accordance with the architecture. When the data is aligned in the memory you don't waste CPU cycles in order to access the data.
This is done for performance reasons (99% of times).

A:

This is "implementation defined", i.e. the alignment requirements are not part of the language specification.
Different CPUs have different requirements on alignment. Some could not address a 16bit value on an uneven address, some could. Some could not address a floating point value unless aligned to an address divisible by its size, some could. And so on. Some would access misaligned data objects more slowly than properly aligned ones, others would trip over an unaligned access.
That is why the language standard does not go into the details of which type needs to be aligned which way (because it couldn't), but left it to the "implementation" -- the compiler backend, in this case.
If you typecast pointers, you might be forcing the code to address a given object at an address where it cannot be addressed. You need to ensure that the alignment requirements of the "old" type are at least as strict as those of the "new" type.
In C++ (C++11 upwards), you get the alignof operator to tell you the alignment requirements of a given type. You also get the alignas operator to enforce a more strict alignment on a given type or object.
In C (C11 upwards), you get the _Alignof and _Alignas operators, which <stdalign.h> wraps into the alignof / alignas convenience macros. (Thanks, Lundin -- C11 is not my forte.)

A:

Some systems can access memory in portions of, say, 32-bit words (4 bytes). It's a hardware limitation. It means that the actual address going into the memory controller should be divisible by four (as it is still addressing the bytes). So once you try to have a word located at address which is not divisible by four, there ate two options - either the compiler will try to generate some fancy code to compose the word out of two memory accesses, but it is not always the case. Sometimes it will just generate a code to access 4 bytes out of the given address. And then the processor will fail with the data alignment error.
Which leads to limitation the language is imposing.
Consider the code (a bad one):
uint8_t a[] = {1,2,3,4,5,6};
uint32_t b = *(uint32_t*)&a[1];

and assume a is aligned to the divisible by four boundary.
Then the second line is trying to read a word out of an address of it's second element, i.e. an address not divisible by four. It will lead to the alignment error. But in C it is simply forbidden by the strict aliasing rule.

