En informática (en particular, en programación ), un valor indefinido es una condición en la que una expresión en un lenguaje de programación no tiene un valor semánticamente correcto en dicho lenguaje, aunque sea sintácticamente correcto. Un valor indefinido no debe confundirse con una cadena vacía , el valor booleano "false" u otros valores "vacíos" (pero definidos). Dependiendo de las circunstancias, la evaluación de un valor indefinido puede provocar una excepción o un comportamiento indefinido , pero en algunos lenguajes de programación los valores indefinidos pueden aparecer durante el curso normal y predecible de la ejecución del programa .
Los lenguajes de tipado dinámico suelen tratar los valores indefinidos de forma explícita cuando es posible. Por ejemplo, Perl tiene undefel operador [ 1 ] que puede "asignar" dicho valor a una variable. En otros sistemas de tipos, un valor indefinido puede significar un valor desconocido e impredecible, o simplemente un fallo del programa al intentar evaluarlo. Los tipos anulables ofrecen un enfoque intermedio; véase más abajo .
Manejo
El valor de una función parcial no está definido cuando su argumento está fuera de su dominio de definición . Esto incluye numerosos casos aritméticos , como la división por cero , la raíz cuadrada o el logaritmo de un número negativo , etc. Otro ejemplo común es el acceso a un array con un índice fuera de rango, al igual que el valor en un array asociativo para una clave que no contiene. En la práctica, existen diversas maneras de manejar estas situaciones:
Valor reservado
En aplicaciones donde se deben manejar valores indefinidos de forma adecuada, es común reservar un valor nulo especial que se distinga de los valores normales. Esto resuelve la dificultad creando un valor definido para representar el caso que antes era indefinido. Existen muchos ejemplos de esto:
- La biblioteca de E/S estándar de C reserva un valor especial
EOFpara indicar que no hay más entradas disponibles. Lagetchar()función devuelve el siguiente carácter de entrada disponible o,EOFsi no hay más, devuelve un valor nulo. (El código de caracteres ASCII define un carácter nulo para este propósito, pero la biblioteca de E/S estándar desea poder enviar y recibir caracteres nulos, por lo que define unEOFvalor independiente). - El estándar de aritmética de punto flotante IEEE 754 define un valor especial " no es un número " que se devuelve cuando una operación aritmética no tiene un valor definido. Algunos ejemplos son la división por cero , la raíz cuadrada o el logaritmo de un número negativo .
- El lenguaje de consulta estructurado (SQL) tiene un valor especial
NULLpara indicar datos faltantes. - El lenguaje Perl permite comprobar la definición de una expresión mediante el
defined()predicado. [ 2 ] - Muchos lenguajes de programación admiten el concepto de puntero nulo, distinto de cualquier puntero válido, y que a menudo se utiliza como valor de retorno de error.
- Algunos lenguajes permiten que la mayoría de los tipos sean anulables, por ejemplo C# . [ 3 ]
- La mayoría de las llamadas al sistema Unix devuelven el valor especial -1 para indicar un fallo.
Si bien los lenguajes de tipado dinámico suelen garantizar que las variables no inicializadas tengan un valor nulo por defecto, los valores de tipado estático a menudo no lo hacen y distinguen los valores nulos (que están bien definidos) de los valores no inicializados (que no lo están). [ 3 ]
Manejo de excepciones
Algunos lenguajes de programación cuentan con un concepto de manejo de excepciones para gestionar los casos en que no se devuelve un valor. La función devuelve un valor de forma predefinida, pero no un valor específico, por lo que no es necesario inventar un valor especial.
Una variante de esto es el manejo de señales , que se realiza a nivel del sistema operativo y no está integrado en un lenguaje de programación. Los manejadores de señales pueden intentar algunas formas de recuperación, como finalizar parte de un cálculo, pero sin la misma flexibilidad que el manejo de excepciones totalmente integrado.
Funciones que no devuelven retorno
Una función que nunca devuelve un valor tiene un valor indefinido porque dicho valor nunca puede observarse. A estas funciones se les asigna formalmente el tipo inferior , que no tiene valores. Los ejemplos se dividen en dos categorías:
- Funciones que se ejecutan en bucle infinito . Esto puede ocurrir deliberadamente o como resultado de la búsqueda de algo que nunca se encontrará. (Por ejemplo, en el caso de un operador μ que falla en una función recursiva parcial ).
- Funciones que finalizan el cálculo, como la
exitllamada al sistema . Desde dentro del programa, esto es indistinguible del caso anterior, pero supone una diferencia para quien invoca el programa.
Comportamiento indefinido
Todos los métodos anteriores para manejar valores indefinidos requieren que se detecte dicha indefinición. Es decir, la función llamada determina que no puede devolver un resultado normal y toma alguna medida para notificar a quien la invocó. En el otro extremo, el comportamiento indefinido obliga a quien llama a evitar invocar una función con argumentos fuera de su dominio. No hay límite a lo que puede suceder. En el mejor de los casos, un fallo fácilmente detectable ; en el peor, un error sutil en un cálculo aparentemente no relacionado.
(La definición formal de "comportamiento indefinido" incluye posibilidades aún más extremas, como " detenerse y prenderse fuego " y "hacer que salgan demonios volando de tu nariz". [ 4 ] )
El ejemplo clásico es una referencia de puntero colgante . Desreferenciar un puntero válido es muy rápido , pero determinar su validez puede ser muy complejo. Por lo tanto, el hardware y los lenguajes de bajo nivel como C no validan los punteros antes de desreferenciarlos, sino que transfieren la responsabilidad al programador. Esto ofrece velocidad a costa de la seguridad.
Valor indefinido sensu stricto
La definición estricta de un valor indefinido es una salida superficialmente válida (no nula) que carece de significado pero que no desencadena un comportamiento indefinido. Por ejemplo, pasar un número negativo a la función rápida de raíz cuadrada inversa producirá un número. No es un número muy útil, pero el cálculo se completará y devolverá algo .
Los valores indefinidos son especialmente frecuentes en el hardware. Si un cable no transporta información útil, sigue existiendo y tiene cierto nivel de voltaje. Este voltaje no debería ser anormal (por ejemplo, no debería producirse una sobretensión dañina ), pero el nivel lógico específico es irrelevante.
La misma situación se presenta en el software cuando se proporciona un búfer de datosstrftime , pero este no se llena por completo. Por ejemplo, la función de la biblioteca C convierte una marca de tiempo a un formato legible para humanos en un búfer de salida proporcionado. Si el búfer de salida no tiene el tamaño suficiente para contener el resultado, se devuelve un error y el contenido del búfer queda indefinido.
En la otra dirección, la openllamada al sistema en POSIX toma tres argumentos: un nombre de archivo, algunas banderas y un modo de archivo. El modo de archivo solo se usa si las banderas incluyen O_CREAT. Es común usar una forma de dos argumentos de open, que proporciona un valor indefinido para el modo de archivo, cuando O_CREATse omite.
En ocasiones, resulta útil trabajar con valores indefinidos de forma limitada. El cálculo general puede seguir estando bien definido si posteriormente se ignora el valor indefinido.
Como ejemplo de esto, el lenguaje C permite convertir un puntero a un entero, aunque el valor numérico de dicho entero no esté definido. Aun así, puede resultar útil para la depuración, para comparar dos punteros y comprobar si son iguales, o para crear una lista enlazada XOR .
En los sistemas de control de concurrencia optimista , que detectan las condiciones de carrera a posteriori, es fundamental gestionar de forma segura los valores indefinidos . Por ejemplo, leer una variable compartida protegida por un bloqueo secuencial generará un valor indefinido antes de determinar que se ha producido una condición de carrera. En ese caso, se descartarán los datos indefinidos y se reintentará la operación. Esto produce un resultado definido siempre que las operaciones realizadas sobre los valores indefinidos no generen un comportamiento completamente indefinido.
Otros ejemplos de utilidad de los valores indefinidos son los generadores de números aleatorios y las funciones hash . Los valores específicos que devuelven no están definidos, pero poseen propiedades bien definidas y pueden utilizarse sin errores.
Notación
En la teoría de la computabilidad , la indefinición de una expresión se denota como expr ↑, y la definición como expr ↓.
Véase también
Referencias
- ↑ "undef" . Documentación de Perl 5. 25/09/2009 . Consultado el 26/03/2010 .
- ↑ "definido" . Documentación de Perl 5. 25/09/2009 . Consultado el 26/03/2010 .
- 1 2 Carr, Richard (2006-10-01). "Tipos de datos numéricos anulables en C#" . Tutorial de fundamentos de C# . Archivado del original el 21-01-2007 . Recuperado el 27-03-2010 .
- ↑ "Demonios nasales" . Archivo de jerga . Consultado el 12 de junio de 2014 .
- Anomalías de software
- Teoría de la computación