38 votes

Est "-1 >> 5;" comportement non spécifié en C?

C11 §6.5.7 Paragraphe 5:

Le résultat de l' E1 >> E2 est E1 décalés vers la droite E2 de positions de bits. Si E1 a un type non signé ou si E1 a signé un type et d'un non négatif, la valeur du résultat est la partie intégrante de la quotient de E1 / 2*^E2. Si E1 a signé un type et un négatif valeur, la valeur résultante de la mise en œuvre est définie.

Mais, Le viva64 document de référence dit:

int B;
B = -1 >> 5; // unspecified behavior

J'ai couru ce code sur GCC et c'est toujours donner une sortie -1.

Donc, standard de dire que "Si E1 a signé un type et une valeur négative, la valeur résultante de la mise en œuvre est définie", Mais que le document de dire que -1>>5; est un comportement non spécifié.

Alors, Est - -1>>5; comportement quelconque dans C? Ce qui est correct?

39voto

dbush Points 8590

Les deux sont corrects. La mise en œuvre définies comportement est un type particulier de comportement quelconque.

Invoquant l'article 3.4.1 de la norme , qui définit la mise en œuvre définies par le comportement":

1 mise en œuvre définies par le comportement

un comportement non spécifié où chaque mise en œuvre des documents de la façon dont le choix est fait

2 EXEMPLE d'Un exemple de mise en œuvre définies par le comportement est le mode de multiplication de la haute-bit afin de lorsqu'un entier signé est décalé à droite.

À partir de la section 3.4.4 la définition de "comportement non spécifié":

1 comportement non spécifié

l'utilisation d'une valeur indéterminée, ou d'autres où ce comportement Norme internationale fournit des deux ou plus de possibilités et impose pas de nouvelles exigences, qui est choisi dans tous les cas

2 EXEMPLE d'Un exemple de comportement quelconque est l'ordre dans lequel les arguments d'une fonction sont évalués.

Comme pour GCC, vous obtiendrez toujours la même réponse car l'opération est définie par l'implémentation. Il met en œuvre décalage à droite des nombres négatifs via l'extension du signe

À partir de la GCC de la documentation:

Les résultats de certaines opérations bit à bit sur les entiers signés (C90 6.3, C99 et C11 6.5).

Les opérateurs sur les bits loi sur la représentation de la valeur, y compris à la fois le signe et la valeur de bits, où le bit de signe est considéré comme immédiatement au-dessus de la plus haute valeur du bit. Signée >> agit sur les nombres négatifs par l'extension du signe.

Comme une extension du langage C, GCC ne pas utiliser la latitude donnée en C99 et C11 seulement pour traiter certains aspects de l'signée <<comme undefined. Toutefois, -fsanitize=shift (et -fsanitize=undefined) sera diagnostiquer de tels cas. Ils sont également diagnostiqués constante les expressions sont nécessaires.

14voto

skrrgwasme Points 3836

"Comportement non spécifié" et "mise en oeuvre définie" ne sont pas contradictoires. Cela signifie simplement que la norme C ne spécifie pas ce qui doit se passer et que diverses implémentations peuvent faire ce qu'elles jugent "correct".

L'exécuter plusieurs fois sur un compilateur et obtenir le même résultat signifie uniquement que ce compilateur est cohérent. Vous pouvez obtenir des résultats différents sur un compilateur différent.

2voto

Antti Haapala Points 11542

La mise en œuvre définies par le comportement est une sous-classe d'une quelconque comportement, c'est à dire un comportement qui n'est pas spécifiée par la norme.

Vice-Rapport n ° 154 de C89 demandé à la commission quelles sont les limites à la mise en œuvre définies par le comportement; le comité de réponses qu'une mise en œuvre peut définir n'importe quel comportement il veut, et qui n'a pas besoin d'être constant.

Quelle mise en œuvre doit faire, est de documenter la façon dont ce choix est fait, par opposition à l'autre classe de quelconque lieu à un comportement conforme de la mise en œuvre devez même pas la peine de raconter comment le choix est fait, peut-être parce que pour ces cas, la majorité des implémentations le texte dirais "au hasard" ou "en fonction de l'optimisation du compilateur niveau" ou "en fonction de l'allocation de registres pour les variables locales".

2voto

Lundin Points 21616

Je n'ai pas tout de le présenter leurs réponses. La norme dit clairement que le droit-la vitesse d'un nombre négatif est la mise en œuvre définies par le comportement. C'est pas un comportement non spécifié, ce qui signifie quelque chose d'autre. Comme vous l'avez bien citer (C17 6.5.7 §5):

Le résultat de E1 >> E2 E1 décalés vers la droite E2 positions de bits. /--/
Si E1 a signé un type et une valeur négative, la valeur résultante de la mise en œuvre est définie.

Cela signifie que le compilateur doit documenter la façon dont il se comporte. Période.

En pratique: le document doit dire si le compilateur utilise l'arithmétique décalage à droite ou logique décalage à droite.


C'est par opposition à un comportement non spécifié, qui est spécifique à l'implémentation comportement qui n'a pas besoin d'être documenté. Un comportement non spécifié est utilisé dans deux cas:

  • Lorsque le comportement du compilateur pourrait être une mise en œuvre un secret que le fournisseur de compilateur ne devraient pas être contraints de révéler à leurs concurrents.
  • Lorsque le compilateur ne peut pas être pris la peine de documenter la façon dont les détails sous-jacents tels que les OS et la mémoire RAM de cellules de mémoire de travail.

Par exemple, un compilateur n'a pas besoin de document de l'ordre de l'évaluation dans le code comme ceci:

a  = f1() + f2();
a += f1() + f2();

Documenter l'ordre dans lequel les sous-expressions sont évaluées permettrait de révéler des détails sur la façon dont le compilateur interne de l'arborescence d'expression et l'optimiseur de travail qui permettraient de révéler pourquoi un compilateur génère un code de meilleure qualité ou compile plus rapide que la concurrence. Ce fut une grande chose lorsque la norme a été écrit à l'origine. Moins le cas aujourd'hui, quand il y a certains grands open-source de compilateurs, de sorte qu'il n'est plus un secret.

De même, un compilateur n'a pas besoin de documenter ce que ce code imprime:

int a;
int ptr = &a;
printf("%d", *ptr);

a est une période indéterminée, la valeur et la sortie est non spécifié - dans la pratique, la production dépend de ce qui était stocké en particulier la RAM de la cellule avant. Ce que nous appelons un "la valeur d'ordures". (Avant de crier "UB", voir (Pourquoi) est d'utiliser une variable non initialisée comportement indéfini?).

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