¿Cuándo la conversión entre tipos de puntero no es un comportamiento indefinido en C?

Como recién llegado a C, estoy confundido acerca de cuándo lanzar un puntero está realmente bien.

Según tengo entendido, puedes lanzar prácticamente cualquier tipo de puntero a cualquier otro tipo, y el compilador te permitirá hacerlo. Por ejemplo:

int a = 5;
int* intPtr = &a;
char* charPtr = (char*) intPtr; 

Sin embargo, en general, esto invoca un comportamiento indefinido (aunque sucede que funciona en muchas plataformas). Dicho esto, parece haber algunas excepciones:

puedes lanzar hacia y desdevoid* libremente (?)puedes lanzar hacia y desdechar* libremente (?)

(Al menos lo he visto en código ...).

Entonces, ¿qué conversiones entre los tipos de puntero sonno comportamiento indefinido en C?

Editar:

Intenté buscar en el estándar C (sección "6.3.2.3 Punteros", enhttp://c0x.coding-guidelines.com/6.3.2.3.html ), pero realmente no lo entendí, aparte del bit sobrevoid*.

Edit2:

Solo para aclarar: explícitamente solo estoy preguntando sobre punteros "normales", es decirno sobre punteros de función. Me doy cuenta de que las reglas para emitir punteros de función son muy restrictivas. De hecho, ya he preguntado sobre eso :-):¿Qué sucede si lanzo un puntero de función, cambiando la cantidad de parámetros?

Respuestas a la pregunta(5)

Su respuesta a la pregunta