¿Cuál es la diferencia entre un puntero que apunta a una ubicación 0x0 y un puntero establecido en NULL?

12

¿Un puntero que apunta a 0x0000 es lo mismo que un puntero establecido en NULL? Si el valor NULL se define en el lenguaje C, ¿a qué ubicación se traduce físicamente? ¿Es lo mismo que 0x0000? ¿Dónde puedo encontrar más detalles sobre estos conceptos?

Arpith
fuente
1
Esto ya se ha pedido en Stack Overflow - stackoverflow.com/questions/1296843/… . Creo que es límite para nosotros, pero estoy dispuesto a darle el beneficio de la duda por el momento.
ChrisF

Respuestas:

12

Un punto que la mayoría de las respuestas aquí no están abordando, al menos no explícitamente, es que un puntero nulo es un valor que existe durante la ejecución, y una constante de puntero nulo es una construcción sintáctica que existe en el código fuente C.

Una constante de puntero nulo , como dice correctamente la respuesta de Karlson, es una expresión constante entera con el valor 0 (un simple 0es el ejemplo más común) o una expresión de ese tipo convertida a void*(como (void*)0).

NULLes una macro, definida en <stddef.h>y varios otros encabezados estándar, que se expande a una constante de puntero nulo definida por la implementación . La expansión generalmente es 0o ((void*)0)(los paréntesis externos son necesarios para satisfacer otras reglas del lenguaje).

Entonces, un literal 0, cuando se usa en un contexto que requiere una expresión de tipo puntero, siempre se evalúa como un null pointervalor de puntero único que no apunta a ningún objeto. Eso no implica nada sobre la representación de un puntero nulo . Los punteros nulos se representan comúnmente como todos los bits cero, pero se pueden representar como cualquier cosa. Pero incluso si un puntero nulo se representa como 0xDEADBEEF, 0o (void*)0sigue siendo una constante de puntero nulo .

Esta respuesta a la pregunta sobre stackoverflow cubre esto bien.

Esto implica, entre otras cosas, que memset()o calloc(), que puede establecer una región de memoria en todos los bits cero, no establecerá necesariamente ningún puntero en esa región en punteros nulos. Es probable que lo hagan en la mayoría de las implementaciones, pero el lenguaje no lo garantiza.

No sé por qué esta pregunta no se considera un duplicado de esta , o cómo es de actualidad aquí.

Keith Thompson
fuente
1
Una de mis molestias con el diseño y la evolución de C es que el dígito cero se ha seguido utilizando como una representación no obsoleta de un puntero nulo. En los primeros días del lenguaje (por ejemplo, antes del advenimiento de cosas como prototipos de funciones), los punteros y los enteros eran lo suficientemente intercambiables como para que usar "0" para un puntero nulo fuera simple y "simplemente funcionara". Sin embargo, una vez que se hizo necesario distinguir entre la cantidad entera cero y un puntero nulo, la representación "0" debería haber quedado en desuso en favor de una palabra clave o secuencia de operador.
supercat
¿Significa esto que el puntero NULL puede apuntar a alguna ubicación cuando se le asigna NULL dependiendo de la plataforma? La constante de puntero nulo puede ser una construcción sintáctica, pero ¿qué sucede exactamente cuando se ejecuta el código? Supongamos que esta construcción sintáctica ha sido compilada en la plataforma GNU / Linux. ¿Cuál es el valor del puntero cuando le asignamos NULL? ¿Cómo difiere esta dirección de cualquier otra dirección?
Arpith
1
@Arpith: la asignación NULL, o cualquier constante de puntero nulo , a un objeto puntero establece el valor de ese objeto en un puntero nulo . En el nivel de la máquina, puede apuntar a algún fragmento de memoria válido. Anular la referencia a un puntero nulo tiene un comportamiento indefinido; Acceder a un trozo de memoria en la dirección 0x0000000es un comportamiento válido, como lo es literalmente cualquier otra cosa. Esa dirección difiere de cualquier otra dirección por (a) comparar igual a NULL, y (b) comparar desigual a cualquier puntero a un objeto C. Un puntero nulo es un valor de puntero arbitrario utilizado para indicar que no apunta a nada.
Keith Thompson, el
1
En el nivel de la máquina, puede apuntar a una porción de memoria válida, pero en la mayoría de los entornos C apuntará a una memoria no válida para que cualquier intento de usar el puntero resulte en una trampa / falla / excepción de hardware. Por lo general, solo se encuentra en las plataformas de hardware más simples, aquellas que no admiten la administración de memoria, donde un puntero NULL apunta a una ubicación de memoria válida.
Solomon Slow
7

Cada plataforma es libre de definir NULL como le plazca.

Según el Estándar C, si asigna cero a un puntero, se convertirá en un valor NULL (para esa plataforma). Sin embargo, si toma un puntero NULL y lo convierte en int, no hay garantías de que obtendrá cero en cada plataforma por ahí. Sin embargo, el hecho es que en la mayoría de las plataformas será cero.

Puede encontrar información sobre esas cosas en The C Language Specification . Una fuente, cuya fiabilidad no puedo garantizar, es esta: http://www.winapi.co.kr/pds/doc/ISO-C-FDIS.1999-04.pdf

Mike Nakis
fuente
2
Si eligen romper con el estándar, son libres de redefinir NULL pointer constant. Hasta donde sé, no hay compiladores que lo hagan.
Karlson
¿Hay algún compilador por ahí que no implemente NULL como 0? ¿Y se garantiza que NULL se evaluará como falso?
Ugoren
NULL está garantizado para evaluar a falso por el estándar. No sé si hay algún compilador (plataforma, en realidad) que no implemente NULL como 0, y lo dudo seriamente, pero el estándar no lo prohíbe, así que quién sabe.
Mike Nakis
Hay confusión entre la representación de la "constante de puntero nulo" abstracta (como se menciona en la especificación) en la memoria, que puede ser como el creador de la plataforma complace y la definición de NULLmacro, que debe expandirse 0en C ++ y en C 0o (void *)0, porque esa es la verdadera "constante de puntero nulo".
Jan Hudec
Si bien NULL puede definirse en teoría como cualquier cosa, sin embargo, el estándar garantiza que una constante int con el valor 0 ingresado en un puntero dará como resultado un puntero nulo (ISO 9899: 1999 6.3.2.3/3). La macro NULL de stddef.h debe ser un puntero nulo (7.17 / 3), por lo que sería muy pesado para el compilador no implementar NULL como 0 o (void *) 0.
1

Se define en el lenguaje C porque no hay una sola dirección de máquina invariable a la que equivale. Si lo hiciera, ¡no necesitaríamos una abstracción de él! Aunque en la mayoría de las plataformas, NULL podría implementarse eventualmente como 0 de algún tipo u otro, simplemente es incorrecto suponer que esto es universal, si le importa la portabilidad.

Kilian Foth
fuente
Eso es lo que las normas son para open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
Karlson
0

De acuerdo con la sección del documento estándar C6.3.2.3 :

Una expresión constante entera con el valor 0, o una expresión de este tipo para escribir void *, se llama constante de puntero nulo.55) Si una constante de puntero nulo se convierte en un tipo de puntero, el puntero resultante, llamado puntero nulo, es garantizado para comparar desigual a un puntero a cualquier objeto o función.

Hasta ahora no he visto un compilador que se haya separado de esto.

Karlson
fuente
@ PéterTörök Tienes razón, es un error. :)
Karlson
1
Sí, pero tenga en cuenta que no dice nada sobre el puntero que realmente tiene un valor numérico de 0. Puede que no lo haga, aunque en la mayoría de las plataformas sí lo hace.
Jan Hudec