OK... I'm a beginner at the whole quoting the Standard thing, but here
goes:
6.3.4 ... A pointer to an object or incomplete type can be converted
to a pointer to a different object or a different incomplete type. The
resulting pointer might not be valid if it is improperly aligned for
the type pointed to. It is guaranteed, however, that a pointer to an
object of a given alignment can be converted to a pointer to an object
of the same alignment or less strict alignment, and back again. The
result is equal to the original pointer. (An object of character type
has the least strict alignment.)
So converting char * to unsigned * means converting from char (which
has the least strict alignment) to something else (which therefore has
the same or more strict alignment). So there might be undefined
behavior, depending on the alignments in question. And if you have no
way of knowing when you write a line of code whether or not it will
produce undefined behavior when the program is run, it might be
prudent to assume the worst.
On the other hand, converting an unsigned * to a char * would be
guaranteed to "work", at least in the weak sense that you get a valid
pointer out. And you could also convert a char * to an unsigned *,
but /only if you knew it had arisen by a previous conversion from
unsigned * to char *./
unsigned 32 bits (in some strange and exotic implementation X that
most people will never encounter

). Then the following code:
char c='a';
unsigned *p=(unsigned *) &c;
unsigned u=*p;
produces undefined behavior for another reason, i.e. the dereferencing
will read three bytes beyond the memory allocated for storing c.