Comportamiento no especificado

Comportamiento no especificado ( ing.  comportamiento no especificado ) y comportamiento definido por la implementación ( ing.  comportamiento definido por la implementación ): el comportamiento de un programa de computadora , que puede variar en diferentes plataformas y compiladores, ya que la especificación del lenguaje de programación ofrece varias opciones válidas para implementar un determinada construcción del lenguaje. A diferencia del comportamiento no definido , un programa con comportamiento no especificado no se considera erróneo desde el punto de vista del cumplimiento de la especificación del lenguaje; con un comportamiento no especificado, la especificación suele limitar los posibles comportamientos, aunque no los reduce a uno solo aceptable.

La diferencia entre los dos es que el comportamiento está definido por la implementación, documentado y consistente en un procesador, entorno, versión del sistema, etc., en modo de emergencia.

El programador debe evitar un comportamiento no especificado en lugares donde es fundamental para el resultado del programa; por ejemplo, si se llama a dos funciones en un orden no especificado y comparten código de depuración, esto será visible en el registro de depuración , pero es posible que no. ser crítico para el resultado. Un programador que escribe para una plataforma puede apegarse a su propia implementación. Y si escribe un programa multiplataforma, debe tener en cuenta todos los casos razonables de comportamiento definidos por la implementación.

Terminología

De acuerdo con el estándar de lenguaje C99 ,

Texto original  (inglés)[ mostrarocultar] 3.4.1 comportamiento definido por la implementación

comportamiento no especificado donde cada implementación documenta cómo se hace la elección

[…]

3.4.3 comportamiento no especificado

uso de un valor no especificado, u otro comportamiento donde esta Norma Internacional proporciona dos o más posibilidades y no impone requisitos adicionales sobre cuál se elige en cualquier caso — ISO/CEI 9899:201x [1]

Según el estándar del lenguaje C++ ,

Texto original  (inglés)[ mostrarocultar] 1.3.5 comportamiento definido por la implementación

comportamiento, para una construcción de programa bien formada y datos correctos, que depende de la implementación y que cada implementación deberá documentar.

[…]

1.3.13 comportamiento no especificado

comportamiento, para una construcción de programa bien formada y datos correctos, eso depende de la implementación. No se requiere que la implementación documente qué comportamiento ocurre. [Nota: por lo general, la gama de posibles comportamientos está delineada por esta Norma Internacional. ]

— ISO/CEI 14882:2003(E)

Ejemplos

En C y C++ (a diferencia del lenguaje Java ), no se especifica el orden en que se evalúan los parámetros de la función; por lo tanto, en el siguiente programa, el orden en que se imprimirán las cadenas "F" y "G" depende del compilador.

#incluir <iostream> int f () { std :: cout << "F" << std :: endl ; devolver 3 ; } entero ( ) { std :: cout << "G" << std :: endl ; devolver 4 ; } int h ( int yo , int j ) { devuelve i + j ; } int principal () { devuelve h ( f (), g ()); }

El ejemplo clásico de comportamiento definido por la implementación (comportamiento no especificado que debe ser documentado por las implementaciones) es el tamaño de los tipos de datos; por ejemplo, long en varios compiladores y sistemas operativos puede tener una longitud de 32 o 64 bits. Un programa que asume que un solo largo siempre se ajustará a un puntero no funcionará correctamente en algunas plataformas (por ejemplo, en Windows x64 ) [2] .

Aquí hay dos implementaciones de la raíz cuadrada inversa rápida : la implementación de Carmack  - Abrash ( Quake III ) y la implementación de C ++ 20 de la Wikipedia en inglés:

float Q_rsqrt ( número flotante ) { yo largo ; flotar x2 , y ; const float tres mitades = 1.5F ; x2 = número * 0.5F ; y = número ; i = * ( largo * ) & y ; // piratería malvada de nivel de bit de punto flotante i = 0x5f3759df - ( i >> 1 ); // ¿Qué diablos? y = * ( flotante * ) & yo ; y = y * ( tres mitades - ( x2 * y * y ) ); // 1ra iteración // y = y * (tres mitades - (x2 * y * y)); // 2da iteración, esto se puede eliminar devolver y ; } constexpr float Q_rsqrt ( número flotante ) noexcept { static_assert ( std :: numeric_limits < float >:: is_iec559 ); float const y = std :: bit_cast < float > ( 0x5f3759df - ( estándar :: bit_cast < estándar :: uint32_t > ( número ) >> 1 )); devuelve y * ( 1.5f - ( número * 0.5f * y * y )); }

El primero está hecho para Windows y Linux de 32 bits, el segundo es más universal: da un error de compilación si la máquina tiene tipos fraccionarios no estándar; No requiere mucho tiempo para ser de 32 bits.

Véase también

Notas

  1. Borrador del Comité ISO/IEC 9899:201x - 11 de agosto de  2008 . Consultado el 1 de diciembre de 2009. Archivado desde el original el 11 de abril de 2012.
  2. ↑ tamaño del tipo de entero largo en diferentes arquitecturas y sistemas operativos  . Red de software Intel. Consultado el 1 de diciembre de 2009. Archivado desde el original el 11 de abril de 2012.

Enlaces