En informática , un puntero nulo o una referencia nula es un valor guardado para indicar que el puntero o la referencia no se refiere a un objeto válido . Los programas utilizan habitualmente punteros nulos para representar condiciones como el final de una lista de longitud desconocida o la imposibilidad de realizar alguna acción; Este uso de punteros nulos se puede comparar con tipos que aceptan valores NULL y con el valor Nothing en un tipo de opción .
Un puntero nulo no debe confundirse con un puntero no inicializado : se garantiza que un puntero nulo no será igual a cualquier puntero que apunte a un objeto válido. Sin embargo, en general, la mayoría de los idiomas no ofrecen dicha garantía para punteros no inicializados. Podría compararse con otros indicadores válidos; o podría compararse con punteros nulos. Podría hacer ambas cosas en diferentes momentos; o la comparación podría ser un comportamiento indefinido . Además, en los lenguajes que ofrecen dicho soporte, el uso correcto depende de la experiencia individual de cada desarrollador y de las herramientas linter. Incluso cuando se usan correctamente, los punteros nulos son semánticamente incompletos , ya que no ofrecen la posibilidad de expresar la diferencia entre un valor "No aplicable" versus un valor "No conocido" o versus un valor "Futuro".
Debido a que un puntero nulo no apunta a un objeto significativo, un intento de acceder a los datos almacenados en esa ubicación de memoria (no válida) puede causar un error de tiempo de ejecución o una falla inmediata del programa. Este es el error de puntero nulo . Es uno de los tipos más comunes de debilidades del software, [1] y Tony Hoare , quien introdujo el concepto, se ha referido a él como un "error de mil millones de dólares".
En C , se garantiza que dos punteros nulos de cualquier tipo serán iguales. [2] La macro del preprocesador NULL
se define como una constante de puntero nulo definida por la implementación en , [3] que en C99 se puede expresar de forma portátil como , el valor entero convertido al tipo (consulte puntero al tipo nulo ). [4] El estándar C no dice que el puntero nulo sea el mismo que el puntero a la dirección de memoria 0, aunque ese puede ser el caso en la práctica. Desreferenciar un puntero nulo es un comportamiento indefinido en C, [5] y una implementación conforme puede asumir que cualquier puntero al que se le desreferencia no es nulo.<stdlib.h>
((void *)0)
0
void*
En la práctica, desreferenciar un puntero nulo puede resultar en un intento de lectura o escritura desde una memoria que no está asignada, lo que desencadena una falla de segmentación o una violación de acceso a la memoria. Esto puede manifestarse como una falla del programa o transformarse en una excepción de software que puede ser detectada por el código del programa. Sin embargo, hay determinadas circunstancias en las que este no es el caso. Por ejemplo, en el modo real x86 , la dirección se puede leer y, por lo general, también se puede escribir, y eliminar la referencia a un puntero a esa dirección es una acción perfectamente válida, pero generalmente no deseada, que puede generar un comportamiento indefinido pero que no bloquea la aplicación. Hay ocasiones en las que desreferenciar el puntero a la dirección cero es intencional y está bien definido; por ejemplo, el código BIOS escrito en C para dispositivos x86 en modo real de 16 bits puede escribir la tabla de descriptores de interrupción (IDT) en la dirección física 0 de la máquina eliminando la referencia a un puntero nulo para escritura. También es posible que el compilador optimice la desreferencia del puntero nulo, evitando un error de segmentación pero provocando otros comportamientos no deseados. [6]0000:0000
En C++, si bien la NULL
macro se heredó de C, tradicionalmente se ha preferido el literal entero para cero para representar una constante de puntero nulo. [7] Sin embargo, C++ 11 introdujo la constante nullptr
y el tipo de puntero nulo explícito nullptr_t
que se utilizará en su lugar.
En algunos entornos de lenguaje de programación (al menos una implementación patentada de Lisp, por ejemplo), [ cita necesaria ] el valor utilizado como puntero nulo (llamado nil
en Lisp ) puede en realidad ser un puntero a un bloque de datos internos útiles para la implementación (pero no accesible explícitamente desde los programas de usuario), permitiendo así utilizar el mismo registro como una constante útil y una forma rápida de acceder a los componentes internos de la implementación. Esto se conoce como nil
vector.
En lenguajes con una arquitectura etiquetada , un puntero posiblemente nulo se puede reemplazar con una unión etiquetada que impone el manejo explícito del caso excepcional; de hecho, un puntero posiblemente nulo puede verse como un puntero etiquetado con una etiqueta calculada.
Los lenguajes de programación utilizan diferentes literales para el puntero nulo . En Python, por ejemplo, un valor nulo se llama None
. En Pascal y Swift , se llama a un puntero nulo nil
. En Eiffel , se llama void
referencia.
Debido a que un puntero nulo no apunta a un objeto significativo, un intento de desreferenciar (es decir, acceder a los datos almacenados en esa ubicación de memoria) un puntero nulo generalmente (pero no siempre) causa un error de tiempo de ejecución o una falla inmediata del programa. MITRE enumera el error del puntero nulo como una de las debilidades del software más comúnmente explotadas. [8]
nil
representa un puntero nulo a la primera dirección en la memoria que también se utiliza para inicializar variables administradas. Al eliminar la referencia, se genera una excepción del sistema operativo externo que se asigna a una EAccessViolation
instancia de excepción de Pascal si la System.SysUtils
unidad está vinculada en la uses
cláusula.NullPointerException
(NPE), que puede ser detectado por el código de manejo de errores, pero la práctica preferida es garantizar que tales excepciones nunca ocurran.nil
es un objeto de primera clase . Por convención, (first nil)
es nil
, tal cual (rest nil)
. Por lo tanto, desreferenciar nil
en estos contextos no causará un error, pero el código mal escrito puede entrar en un bucle infinito.NullReferenceException
se genere a. Aunque detectarlas generalmente se considera una mala práctica, el programa puede detectar y manejar este tipo de excepción.nil
objeto (que es un puntero nulo) sin que se interrumpa el programa; el mensaje simplemente se ignora y el valor de retorno (si lo hay) es nil
o 0
, según el tipo. [9]Existen técnicas para facilitar la depuración de desreferencias de punteros nulos. [11] Bond y otros. [11] sugieren modificar la máquina virtual Java (JVM) para realizar un seguimiento de la propagación nula.
Los lenguajes funcionales puros y el código de usuario ejecutados en muchos lenguajes interpretados o de máquinas virtuales no sufren el problema de la desreferenciación del puntero nulo, ya que no se proporciona acceso directo a los punteros y, en el caso de los lenguajes funcionales puros, todo el código y los datos son inmutables.
Cuando un lenguaje proporciona o utiliza punteros que de otro modo podrían quedar nulos, es posible mitigar o evitar las desreferencias nulas en tiempo de ejecución proporcionando verificación en tiempo de compilación a través de análisis estático u otras técnicas, con un creciente movimiento hacia la asistencia sintáctica de características del lenguaje como los que se ven en las versiones modernas del lenguaje de programación Eiffel , [12] D , [13] y Rust . [14]
Se pueden realizar análisis similares utilizando herramientas externas, en algunos idiomas.
Como regla general, para cada tipo de estructura o clase, defina algunos objetos que representen algún estado de la lógica empresarial reemplazando el comportamiento indefinido en nulo. Por ejemplo, "futuro" para indicar un campo dentro de una estructura que no estará disponible en este momento (pero que sabemos de antemano que en un futuro se definirá), "no aplicable" para indicar un campo en una estructura no normalizada estructura, "error", "tiempo de espera" para indicar que el campo no se pudo inicializar (probablemente deteniendo la ejecución normal del programa, subproceso, solicitud o comando completo).
En 2009, Tony Hoare declaró [15] [16] que inventó la referencia nula en 1965 como parte del lenguaje ALGOL W. En esa referencia de 2009, Hoare describe su invento como un "error de miles de millones de dólares":
Yo lo llamo mi error de mil millones de dólares. Fue la invención de la referencia nula en 1965. En ese momento, estaba diseñando el primer sistema de tipos completo para referencias en un lenguaje orientado a objetos (ALGOL W). Mi objetivo era garantizar que todo uso de referencias fuera absolutamente seguro, y que el compilador realizara la verificación automáticamente. Pero no pude resistir la tentación de incluir una referencia nula, simplemente porque era muy fácil de implementar. Esto ha dado lugar a innumerables errores, vulnerabilidades y caídas del sistema, que probablemente han causado mil millones de dólares en dolores y daños en los últimos cuarenta años.
const
NULL
NULL
0-201-88954-4.