Que signifient exactement «IB» et «UB»?

110

J'ai vu les termes «IB» et «UB» utilisés plusieurs fois, en particulier dans le contexte de C ++. J'ai essayé de les rechercher sur Google, mais apparemment, ces combinaisons de deux lettres sont très utiles. : P

Alors, je vous demande ... qu'est-ce que cela veut dire, quand on dit que c'est une mauvaise chose?

cHao
la source
5
Si vous décidez d'annuler les modifications de quelqu'un d'autre, assurez-vous que votre orthographe, votre ponctuation et votre grammaire sont parfaites. Il est inutile d'annuler les modifications qui constituent une amélioration substantielle par rapport au texte d'origine.
Robert Harvey

Réponses:

139

IB: Comportement défini par l'implémentation. Le standard laisse le soin au compilateur / plateforme particulier de définir le comportement précis, mais exige qu'il soit défini.

L'utilisation d'un comportement défini par l'implémentation peut être utile, mais rend votre code moins portable.

UB: comportement indéfini. La norme ne spécifie pas comment un programme invoquant un comportement non défini doit se comporter. Aussi connu sous le nom de «démons nasaux», car théoriquement cela pourrait faire voler des démons hors de votre nez.

Utiliser un comportement non défini est presque toujours une mauvaise idée. Même si cela semble parfois fonctionner, toute modification de l'environnement, du compilateur ou de la plate-forme peut casser votre code de manière aléatoire.

Thomas
la source
11
J'attends toujours qu'un démon sorte du nez de quelqu'un à cause de l'utilisation d'un comportement indéfini en C ++. Je suppose que cela se produira lorsque les premiers compilateurs seront pleinement conformes à la nouvelle norme C ++.
OregonGhost
4
@OregonGhost: Je suppose que vous avez raison. J'ai vu cela arriver avec des licornes à quelques reprises, mais jamais avec des démons.
Thomas
33
@OregonGhost - la norme ne spécifie pas combien de cornes un démon doit avoir.
DVK
5
@Michael Burr: Je préfère "prendre feu". C'est évidemment catastrophique, et cela a au moins un vague air de plausibilité (le matériel informatique prend parfois feu, certes pour des raisons de matériel plutôt que de défaillance logicielle dans le cas de tout système sur lequel vous liriez ce fil).
Steve Jessop
1
C'est drôle comme personne ayant répondu à cette question n'a moins de réputation que 30k.
19

Comportement défini par l'implémentation et comportement indéfini

La norme C ++ est très spécifique sur les effets de diverses constructions, et en particulier, vous devez toujours être conscient de ces catégories de problèmes :

  • Un comportement non défini signifie qu'il n'y a absolument aucune garantie donnée. Le code pourrait fonctionner, mettre le feu à votre disque dur ou faire voler des démons dans votre nez . En ce qui concerne le langage C ++, absolument tout peut arriver. Concrètement, cela signifie généralement que vous avez un bogue irrécupérable. Si cela se produit, vous ne pouvez pas vraiment confiance quoi que ce soit au sujet de votre application (parce que l' un des effets de ce comportement non défini pourrait tout simplement avoir été gâcher la mémoire utilisée par le reste de votre application). Il n'est pas nécessaire d'être cohérent, donc exécuter le programme deux fois peut donner des résultats différents. Cela peut dépendre des phases de la lune, de la couleur de la chemise que vous portez ou de tout autre chose.

  • Un comportement non spécifié signifie que le programme doit faire quelque chose de sain et de cohérent, mais il n'est pas nécessaire de le documenter .

  • Le comportement défini par l'implémentation est similaire à non spécifié, mais doit également être documenté par les rédacteurs du compilateur. Un exemple de ceci est le résultat d'un reinterpret_cast. généralement , il change simplement le type d'un pointeur, sans modifier l'adresse, mais le mappage est en fait défini par l'implémentation, de sorte qu'un compilateur peut mapper vers une adresse complètement différente, tant qu'il a documenté ce choix. Un autre exemple est la taille d'un int. La norme C ++ ne se soucie pas si elle est de 2, 4 ou 8 octets, mais elle doit être documentée par le compilateur

Mais il vaut mieux les éviter. Lorsque cela est possible, respectez le comportement spécifié à 100% par le standard C ++ lui-même. De cette façon, vous êtes assuré de la portabilité.

Vous devez souvent également vous fier à un comportement défini par l'implémentation. Cela peut être inévitable, mais vous devez toujours y prêter attention et être conscient que vous comptez sur quelque chose qui peut changer entre les différents compilateurs.

Par contre, les comportements non définis doivent toujours être évités. En général, vous devez simplement supposer que cela fait exploser votre programme d'une manière ou d'une autre.

jalf
la source
1
UB doit être évité si vous vous souciez de la portabilité . Une implémentation particulière peut définir ce qui se passe pour un comportement non défini spécifique, et dans certains cas (en particulier les pilotes de périphérique et les petits systèmes embarqués), vous devez utiliser ces éléments.
Jerry Coffin
3
@Jerry: Non, UB doit être évité s'il est totalement indéfini . Si la plate-forme / l'implémentation / le runtime / le compilateur donne des garanties supplémentaires, vous pouvez vous fier au comportement et perdre la portabilité. Mais alors ce n'est plus tout à fait aussi indéfini ... La plupart du temps, cependant, vous n'avez pas de telles garanties, et undefined est simplement indéfini et doit être évité à tout prix.
jalf
«cohérent» pourrait être une description trompeuse d'un comportement non spécifié. Il doit être cohérent avec le contexte général de l'opération, par exemple si une expression a une "valeur non spécifiée", le résultat doit être une valeur, si vous la stockez, la valeur stockée doit ensuite se comparer égale à elle-même, et ainsi de suite. Mais les résultats non spécifiés n'ont pas besoin d'être cohérents dans le temps (même sortie pour la même entrée si vous l'exécutez à nouveau), ni même déterministes.
Steve Jessop
"n'est plus aussi indéfini" - c'est exactement comme non défini par la norme , et UB est une signification abrégée non définie par la norme. Dans votre exemple, il est défini par l'implémentation. D'ailleurs, vous pouvez vous fier à un comportement qui n'est pas défini par la norme ou l'implémentation, si vous avez vérifié le code objet et que vous ne prévoyez plus jamais de recompiler ;-)
Steve Jessop
"doit ensuite comparer égal à lui-même". Hmm, sauf si c'est un NaN. Quoi qu'il en soit, il doit avoir le comportement requis de son type.
Steve Jessop
8
  • IB: est le comportement défini par l'implémentation - le compilateur doit documenter ce qu'il fait. L'exécution d'une >>opération sur une valeur négative en est un exemple.

  • UB: comportement indéfini - le compilateur peut tout faire, y compris simplement planter ou donner des résultats imprévisibles. Le déréférencement d'un pointeur nul entre dans cette catégorie, mais aussi des choses plus subtiles comme l'arithmétique du pointeur qui tombe en dehors des limites d'un objet tableau.

Un autre terme apparenté est «comportement non spécifié». C'est en quelque sorte entre les comportements définis par l'implémentation et les comportements indéfinis. pour un comportement non spécifié, le compilateur doit faire quelque chose selon le standard, mais les choix que le standard lui donne appartiennent au compilateur et n'ont pas besoin d'être définis (ni même cohérents). Des choses comme l'ordre d'évaluation des sous-expressions appartiennent à cette catégorie. Le compilateur peut les exécuter dans l'ordre de son choix et pourrait le faire différemment dans différentes versions ou même dans différentes exécutions de la même version (peu probable, mais autorisé).

Michael Burr
la source
4

La version courte:

Comportement défini par l'implémentation (IB): correctement programmé mais indéterminé *

Comportement indéfini (UB): mal programmé (ie un bug !)

*) "indéterminé" en ce qui concerne le standard de langue, il sera bien entendu déterminé sur toute plateforme fixe.

Kerrek SB
la source
Si la norme indique qu'une action invoque le comportement défini par l'implémentation, les implémentations doivent spécifier un comportement cohérent résultant de cette action. Malheureusement, il n'y a pas de catégorie de comportement pour laquelle une mise en œuvre serait tenue de spécifier les conséquences possibles, mais ne serait pas tenue d'avoir une conséquence particulière de manière cohérente.
supercat du