89 votes

Code qui ne sera jamais exécuté peut appeler des comportement indéfini ?

Le code qui appelle un comportement non défini (dans cet exemple, la division par zéro) sera jamais exécuté, est le comportement du programme encore indéfini ?

Je pense que c’est encore un comportement indéfini, mais je ne trouve aucune preuve dans la norme de soutenir ou de me refuser.

Alors, des idées ?

73voto

Keith Thompson Points 85120

Regardons comment la norme définit les termes de comportement "et "un comportement non défini".

Les références sont à la N1570 projet de l'ISO C 2011 standard; je ne suis pas au courant de toutes les différences pertinentes dans l'une des trois publié ISO normes C (1990, 1999 et 2011).

La Section 3.4:

comportement
l'aspect extérieur ou de l'action

Ok, c'est un peu vague, mais je dirais que l'instruction n'a pas "l'apparence", et certainement pas "d'action", sauf si c'est réellement exécuté.

La Section 3.4.3:

un comportement indéfini
problème, lors de l'utilisation d'un non-compatibles ou erronées programme de construction ou de données erronées, pour lequel la présente Norme Internationale n'impose pas d'exigences

Il dit:"lors de l'utilisation" d'une telle construction. Le mot "utilisation" n'est pas défini par la norme, donc on se rabat sur la commune de la signification (en anglais). Une construction n'est pas "utilisé" s'il n'est jamais exécutée.

Il y a une note en vertu de cette définition:

NOTE Possible un comportement indéfini plages d'ignorer la situation complètement avec des résultats imprévisibles, à se comporter lors de la traduction ou de l'exécution du programme dans documenté de façon caractéristique de l' de l'environnement (avec ou sans émission d'un message de diagnostic), à cessation de la traduction ou de l'exécution (avec l'émission d'un message de diagnostic).

Ainsi, un compilateur est autorisée à rejeter votre programme lors de la compilation si son comportement est indéfini. Mais mon interprétation est qu'il peut le faire seulement si elle peut prouver que chaque exécution du programme rencontrerez un comportement indéfini. Ce qui implique, je pense, que ce:

if (rand() % 2 == 0) {
    i = i / 0;
}

qui certainement peut avoir un comportement indéfini, ne peut pas être rejetée au moment de la compilation.

En pratique, les programmes doivent être en mesure d'effectuer d'exécution des tests pour se prémunir contre l'invocation comportement indéfini, et le standard, afin de leur permettre de le faire.

Votre exemple est:

if (0) {
    i = 1/0;
}

qui ne s'exécute jamais la division par 0. Un très commun langage est:

int x, y;
/* set values for x and y */
if (y != 0) {
    x = x / y;
}

La division a certainement un comportement indéfini si y == 0, mais il n'est jamais exécutée si y == 0. Le comportement est bien défini, et pour la même raison que votre exemple est bien défini: parce que le potentiel de comportement indéfini ne peut jamais se produire.

(À moins d' INT_MIN < -INT_MAX && x == INT_MIN && y == -1 (oui, division entière peut overflow), mais c'est une question distincte.)

Dans un commentaire (supprimé depuis), quelqu'un a souligné que le compilateur peut évaluer des expressions constantes au moment de la compilation. Ce qui est vrai, mais pas dans ce cas, parce que dans le contexte de

i = 1/0;

1/0 n'est pas une expression constante.

Une constante de l'expression est une catégorie syntaxique qui réduit à conditionnelle-l'expression (ce qui exclut les affectations et les virgules expressions). La production constante de l'expression apparaît dans la grammaire seulement dans des contextes qui exigent en réalité une expression constante, tels que des étiquettes. Donc, si vous écrivez:

switch (...) {
    case 1/0:
    ...
}

ensuite, 1/0 est une expression constante-et qui viole la contrainte en 6.6p4: "Chaque expression constante est d'évaluer d'une constante dans la gamme de représentable les valeurs de ce type.", ainsi, un diagnostic est nécessaire. Mais le membre de droite d'une affectation ne nécessite pas une constante de l'expression, un simple conditionnel expression, de sorte que les contraintes sur des expressions constantes ne sont pas applicables. Un compilateur peut évaluer une expression en ce qu'elle peut au moment de la compilation, mais seulement si le comportement est le même, comme si il ont été évalués au cours de l'exécution (ou, dans le contexte de l' if (0), pas évaluée lors de l'exécution().

(Quelque chose qui ressemble exactement à une constante de l'expression n'est pas nécessairement une constante de l'expression, tout comme, en x + y * z, la séquence de x + y n'est pas un additif expression en raison du contexte dans lequel il apparaît.)

Ce qui signifie que la note de bas de page dans N1570 la section 6.6 que j'allais citer:

Ainsi, dans la suite de l'initialisation,
static int i = 2 || 1 / 0;
l'expression est un entier valide expression constante de valeur.

n'est pas réellement pertinente à cette question.

Enfin, il y a quelques choses qui sont définies de façon à provoquer un comportement indéfini qui ne sont pas sur ce qui se passe lors de l'exécution. L'annexe J, section 2 de la norme (de nouveau, voir le N1570 projet) des listes de choses qui peuvent causer un comportement indéfini, réunis le reste de la norme. Quelques exemples (je ne prétend pas que c'est une liste exhaustive) sont:

  • Un non vide de la source de fichier ne se termine pas par un caractère de nouvelle ligne qui n'est pas immédiatement précédé par un caractère barre oblique inverse ou se termine dans un partiel prétraitement jeton ou un commentaire
  • Jeton de concaténation produit une séquence de caractères correspondant à la syntaxe de caractère universel de nom
  • Un caractère qui n'est pas dans la source de base de jeu de caractères est rencontré dans un fichier source, sauf dans un identificateur, une constante de caractère, une chaîne de caractères littéral, un nom d'en-tête, un commentaire, ou un prétraitement jeton qui est jamais converti à un jeton
  • Un identifiant, un commentaire littéral de chaîne de caractères constante, ou le nom d'en-tête contient une séquence de caractères ou de ne pas commencer et à la fin de l'état de décalage initial
  • Le même identifiant a la fois internes et externes de liaison dans la même unité de traduction

Ces cas particuliers sont des choses qu'un compilateur pourrait détecter. Je pense que leur comportement n'est pas défini, car le comité ne voulait pas ou ne pouvait pas, d'imposer le même comportement sur toutes les implémentations, et la définition d'une gamme de comportements n'était tout simplement pas en vaut la peine. Ils n'ont pas vraiment tomber dans la catégorie de "code qui ne sera jamais exécuté", mais je les mentionne ici par souci d'exhaustivité.

31voto

Pascal Cuoq Points 39606

Cet article traite de cette question dans la section 2.6:

int main(void){
      guard();
      5 / 0;
}

Les auteurs considèrent que le programme est défini lors de l' guard() ne met pas fin. Ils se trouvent aussi à distinguer les notions de "statiquement indéterminés" et "dynamique non définie", par ex.:

L'intention derrière le standard11 semble que, en général, les situations sont faite statiquement indéterminés si il n'est pas facile de générer du code pour eux. Seulement lorsque le code peut être généré, alors la situation peut être pas défini de façon dynamique.

11) la correspondance Privée avec des membres du comité.

Je recommande de regarder l'intégralité de l'article. Pris ensemble, il peint une image cohérente.

Le fait que les auteurs de l'article ont pour discuter de la question avec un membre du comité confirme que la norme est actuellement floue sur la réponse à votre question.

6voto

arnaud576875 Points 35281

Dans ce cas, le comportement indéfini est le résultat de l’exécution du code. Donc si le code n’est pas exécuté, il n’y a pas un comportement indéfini.

Code non exécuté peut invoquer un comportement non défini si le comportement indéfini était le résultat d’uniquement la déclaration du code (par exemple si certains cas de l’occultation variable n’était pas définie).

2voto

alk Points 26509

J’irais avec le dernier paragraphe de cette réponse : http://stackoverflow.com/a/18384176/694576

... UB est une question de DUREE, pas un compiletime...

Donc, non, il n’y a aucun UB invoquée.

2voto

Zaibis Points 1616

La norme dit, comme je me souviens bien, il a permis de faire quelque chose dès l’instant où, une règle s’est rompue. Il y a peut-être quelques événements spéciaux avec genre de saveur globale (mais j’ai jamais entendu ou lu quelque chose comme ça)... Donc je dirais : non ce ne peut pas être UB, parce que longtemps le comportement est bien défini 0 est toujours false, alors la règle ne doit pas obtenir répartie sur la durée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X