It's because "unsigned char" is a different type from "unsigned char *". Observe.
Code:
char c;
char *p = &c;
unsigned char uc = (unsigned char)c;
unsigned char *up = (unsigned char *)p;
An unsigned char is (usually) one byte. It usually stores a value from 0 to 255.
A unsigned char * is usually four or eight bytes. It stores the address of another variable, the address of an unsigned char somewhere else in memory.
So unsigned char and unsigned char * are completely different types. You have to tell the compiler which of them you want to use. Both can be used, but both give you very different values.
Code:
unsigned char c = 'a';
unsigned char *anotherp = (unsigned char *)c;
unsigned char anotherc = (unsigned char)c;
The value of anotherp is dubious, but it can be done if you really want to.
Rationale: when specifying types, use the name of the type (like "unsigned char"), as well as any levels of indirection (with asterisks).
Incidentally, casting a float * to an unsigned char * isn't usually much use unless you are trying to examine each byte of the float individually or something.