I was just reading about the bad practice of casting the return value of malloc. If I understood correctly, it is absolutely legal to leave the cast as it is do
There are at least two kinds of casts:
Casts of numeric values that cause a change of representation. (This is a term of art you will find in Harbison and Steele's very helpful C Reference Manual.) These casts are mostly innocuous; the only way you can do harm is by, e.g., casting a wider type to a narrower type, in which case you are deliberately throwing away bits. Only you, the programmer, know whether it's safe to throw away those bits.
C also has an insidious feature that it may perform a change of representation on your behalf when you assign, return, or pass a numeric expression whose type doesn't exactly match the type of the associate lvalue, result, or argument. I think this feature is pernicious, but it is firmly embedded in the C way of doing things. The gcc option -Wconversion will let you know where the compiler is doing a change of representation on your behalf, without being asked.
Casts that don't involve a change of representation but simply ask the compiler to view bits a certain way. These include casts between signed and unsigned types of the same size, as well as casts between pointer types that point to different sorts of data. The type void * enjoys a special status in C as the compiler will convert freely between void * and other data pointer types without a cast. Note that a cast between pointers of two different types of data never involves a change of representation. This is one reason the void * convention can work.
One reason C programmers try to avoid gratuitous casts is that when you write a cast, the compiler trusts you completely. If you make a mistake, the compiler is not going to catch it for you. For this reason I advise my student never to cast pointer types unless they know exactly what they are doing.
P.S. I thought it would be possible to write a short, helpful answer to this question. Wrong!