Desreferenciando el puntero nulo

int* p = 0; int* q = &*p; 

¿Es este comportamiento indefinido o no? Busqué algunas preguntas relacionadas, pero este aspecto específico no apareció.

La respuesta a esta pregunta es: depende de qué estándar de idioma está siguiendo :-).

En C90 y C ++, esto no es válido porque se realiza indirectamente en el puntero nulo (haciendo *p ), y al hacerlo se produce un comportamiento indefinido.

Sin embargo, en C99, esto es válido, bien formado y bien definido. En C99, si el operando del unario- & se obtuvo como resultado de aplicar el unario- * o al realizar la suscripción ( [] ), entonces ni el & ni el * o [] se aplica. Por ejemplo:

 int* p = 0; int* q = &*p; // In C99, this is equivalent to int* q = p; 

Igualmente,

 int* p = 0; int* q = &p[0]; // In C99, this is equivalent to int* q = p + 0; 

De C99 §6.5.3.2 / 3:

Si el operando [del operador & unario] es el resultado de un operador unario * , ni ese operador ni el operador & se evalúan y el resultado es como si ambos se hubieran omitido, excepto que las restricciones sobre los operadores aún se aplican y el resultado no es un lvalue

De manera similar, si el operando es el resultado de un operador [] , ni el operador & ni el unario * implícito en [] se evalúa y el resultado es como si el operador & hubiera eliminado y el operador [] se hubiera cambiado a un operador +

(y su nota al pie, # 84):

Por lo tanto, &*E es equivalente a E (incluso si E es un puntero nulo)

Sí, eso sería un comportamiento indefinido, pero su comstackdor podría optimizar el &* out.

Por qué no está definido, es que está intentando acceder a la memoria fuera de su espacio direccionable.

Sí, desreferenciar el puntero nulo es un comportamiento indefinido. La constante 0 entera en un contexto de puntero es el puntero nulo. Eso es.

Ahora, si su segunda línea fue int *q = p; eso sería una simple asignación de puntero. Si el comstackdor elimina el &* y reduce la desreferencia a una tarea, estás bien.

En mi humilde opinión, en lo que respecta a las dos líneas de código, no hay ningún acceso fuera del espacio de direcciones. La segunda instrucción simplemente toma la dirección de (* p) que sería ‘p’ nuevamente y por lo tanto almacenará ‘0’. Pero nunca se accede a la ubicación.