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é.