¿Qué significan exactamente "IB" y "UB"?

110

He visto los términos "IB" y "UB" usados ​​varias veces, particularmente en el contexto de C ++. He intentado buscarlos en Google, pero aparentemente esas combinaciones de dos letras tienen mucha utilidad. :PAGS

Entonces, les pregunto ... ¿qué quieren decir cuando se dicen como si fueran algo malo?

cHao
fuente
5
Si decide revertir las ediciones de otra persona, asegúrese de que su ortografía, puntuación y gramática sean perfectas. No tiene sentido deshacer las ediciones que son una mejora sustancial con respecto al texto original.
Robert Harvey

Respuestas:

139

IB: Comportamiento definido por la implementación. El estándar deja que el compilador / plataforma en particular defina el comportamiento preciso, pero requiere que se defina.

El uso de un comportamiento definido por la implementación puede ser útil, pero hace que su código sea menos portátil.

UB: Comportamiento indefinido. El estándar no especifica cómo debe comportarse un programa que invoca un comportamiento indefinido. También conocido como "demonios nasales" porque teóricamente podría hacer que los demonios salgan volando de tu nariz.

Usar un comportamiento indefinido casi siempre es una mala idea. Incluso si parece funcionar a veces, cualquier cambio en el entorno, el compilador o la plataforma puede romper el código de forma aleatoria.

Thomas
fuente
11
Todavía estoy esperando a que un demonio salga volando de la nariz de alguien por usar un comportamiento indefinido en C ++. Supongo que sucederá cuando los primeros compiladores cumplan completamente con el nuevo estándar C ++.
OregonGhost
4
@OregonGhost: Supongo que tienes razón. Lo he visto suceder con unicornios un par de veces, pero nunca demonios.
Thomas
33
@OregonGhost: el estándar no especifica cuántos cuernos debe tener un demonio.
DVK
5
@Michael Burr: Prefiero "prender fuego". Es evidentemente catastrófico, y tiene al menos un vago aire de plausibilidad (el hardware de la computadora a veces se incendia, es cierto que por razones de hardware en lugar de fallas de software en el caso de cualquier sistema en el que esté leyendo este hilo).
Steve Jessop
1
Es curioso cómo nadie que haya respondido esta pregunta tiene menos reputación que 30k.
19

Comportamiento definido por la implementación y comportamiento indefinido

El estándar C ++ es muy específico sobre los efectos de varias construcciones y, en particular, siempre debe estar atento a estas categorías de problemas :

  • El comportamiento indefinido significa que no hay absolutamente ninguna garantía. El código podría funcionar, o podría incendiar su disco duro o hacer que los demonios salgan volando por su nariz . En lo que respecta al lenguaje C ++, puede pasar absolutamente cualquier cosa. En términos prácticos, esto generalmente significa que tiene un error irrecuperable. Si esto sucede, realmente no puede confiar en nada acerca de su aplicación (porque uno de los efectos de este comportamiento indefinido podría haber sido arruinar la memoria utilizada por el resto de su aplicación). No es necesario que sea coherente, por lo que ejecutar el programa dos veces puede dar resultados diferentes. Puede depender de las fases de la luna, el color de la camisa que llevas puesta o absolutamente cualquier otra cosa.

  • El comportamiento no especificado significa que el programa debe hacer algo sensato y coherente, pero no es necesario que lo documente .

  • El comportamiento definido por la implementación es similar al no especificado, pero los redactores del compilador también deben documentarlo. Un ejemplo de esto es el resultado de a reinterpret_cast. por lo general , simplemente cambia el tipo de puntero, sin modificar la dirección, pero el mapeo está realmente definido por la implementación, por lo que un compilador podría mapear a una dirección completamente diferente, siempre que documente esta elección. Otro ejemplo es el tamaño de un int. Al estándar C ++ no le importa si tiene 2, 4 u 8 bytes, pero debe estar documentado por el compilador

Pero lo común de todos estos es que es mejor evitarlos. Cuando sea posible, siga el comportamiento 100% especificado por el estándar C ++. De esa manera, tiene la portabilidad garantizada.

A menudo, también debe confiar en algún comportamiento definido por la implementación. Puede ser inevitable, pero aun así debe prestarle atención y ser consciente de que depende de algo que puede cambiar entre diferentes compiladores.

El comportamiento indefinido, por otro lado, siempre debe evitarse. En general, debe asumir que hace que su programa explote de una forma u otra.

jalf
fuente
1
Debe evitar la UB si le preocupa la portabilidad . Una implementación particular puede definir lo que sucede para un comportamiento indefinido específico y, en algunos casos (especialmente controladores de dispositivos y sistemas integrados más pequeños), debe usar esas cosas.
Jerry Coffin
3
@Jerry: No, UB debe evitarse si no está completamente definido . Si la plataforma / implementación / tiempo de ejecución / compilador ofrece más garantías, entonces puede confiar en el comportamiento y perder la portabilidad. Pero entonces ya no es tan indefinido ... La mayoría de las veces, sin embargo, no tiene tales garantías, y undefined es simplemente indefinido, y debe evitarse a toda costa.
jalf
"coherente" puede ser una descripción engañosa de un comportamiento no especificado. Tiene que ser coherente con el contexto general de la operación, por ejemplo, si una expresión tiene un "valor no especificado", el resultado debe ser un valor, si lo almacena, el valor almacenado debe comparar a partir de entonces igual a sí mismo, y así sucesivamente. Pero los resultados no especificados no necesitan ser consistentes a lo largo del tiempo (la misma salida para la misma entrada si lo ejecuta nuevamente), o incluso deterministas.
Steve Jessop
"ya no es tan indefinido": es exactamente como no está definido por el estándar , y UB es un significado abreviado indefinido por el estándar. En su ejemplo, está definido por la implementación. De hecho, puede confiar en un comportamiento que no está definido por el estándar o la implementación, si ha verificado el código objeto y no planea volver a compilar nunca más ;-)
Steve Jessop
"debe a partir de entonces comparar igual a sí mismo". Hmm, a menos que sea un NaN. De todos modos, debe tener cualquier comportamiento que se requiera de su tipo.
Steve Jessop
8
  • IB: es un comportamiento definido por la implementación; el compilador debe documentar lo que hace. Realizar una >>operación en un valor negativo es un ejemplo.

  • UB: comportamiento indefinido: el compilador puede hacer lo que sea, incluso fallar o dar resultados impredecibles. Desreferenciar un puntero nulo cae en esta categoría, pero también cosas más sutiles como la aritmética del puntero que cae fuera de los límites de un objeto de matriz.

Otro término relacionado es "comportamiento no especificado". Esto es una especie de comportamiento entre la implementación definida y la indefinida. para un comportamiento no especificado, el compilador debe hacer algo de acuerdo con el estándar, pero exactamente qué opciones le da el estándar depende del compilador y no necesita ser definido (ni siquiera consistente). Cosas como el orden de evaluación de sub-expresiones entran en esta categoría. El compilador puede realizarlos en el orden que quiera, y podría hacerlo de manera diferente en diferentes compilaciones o incluso en diferentes ejecuciones de la misma compilación (improbable, pero permitido).

Michael Burr
fuente
4

La versión corta:

Comportamiento definido por la implementación (IB): Correctamente programado pero indeterminado *

Comportamiento indefinido (UB): Programado incorrectamente (¡es decir, un error !)

*) "indeterminado" en lo que respecta al estándar del lenguaje, por supuesto, estará determinado en cualquier plataforma fija.

Kerrek SB
fuente
Si el estándar indica que una acción invoca un comportamiento definido por la implementación, se requieren implementaciones para especificar un comportamiento consistente resultante de esa acción. Desafortunadamente, no existe una categoría de comportamiento para la cual se requiera una implementación para especificar las posibles consecuencias, pero no se requeriría que ninguna consecuencia particular ocurra de manera consistente.
supercat