"Puntero desde entero / entero desde puntero sin conversión" emite

sta pregunta está destinada a ser una entrada de preguntas frecuentes para todas las inicializaciones / asignaciones entre números enteros y problemas de puntero.

Quiero escribir código donde un puntero se establece en una dirección de memoria específica, por ejemplo0x12345678. Pero al compilar este código con el compilador gcc, obtengo advertencias / errores "la inicialización hace que el puntero sea un entero sin una conversión":

int* p = 0x12345678;

e manera similar, este código proporciona "la inicialización hace que el entero sea un puntero sin conversión":

int* p = ...;
int i =  p;

Si hago lo mismo fuera de la línea de declaración de variable, el mensaje es el mismo pero dice "asignación" en lugar de "inicialización":

p = 0x12345678; // "assignment makes pointer from integer without a cast"
i = p;          // "assignment makes integer from pointer without a cast"

Las pruebas con otros compiladores populares también dan mensajes de error / advertencia:

clang dice "conversión de entero a puntero incompatible"icc dice "un valor de tipoint no se puede usar para inicializar una entidad de tipoint*"MSVC (cl) dice "inicializandoint* difiere en los niveles de indirección deint ".

Pregunta: ¿Son válidos los ejemplos anteriores C?

Y una pregunta de seguimiento:

Esto no da ninguna advertencia / error:

int* p = 0;

¿Por qué no