Est-ce que “-1 >> 5;” comportement non spécifié en C?

C11 §6.5.7 Paragraphe 5:

Le résultat de E1 >> E2 est E1 positions de bit E2 décalées à droite. Si E1 a un type non signé ou si E1 a un type signé et une valeur non négative, la valeur du résultat est la partie intégrale du quotient de E1 / 2*^E2 . Si E1 a un type signé et une valeur négative, la valeur résultante est définie par l’implémentation.

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

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

J’ai exécuté ce code sur GCC et il donne toujours une sortie -1 .

Ainsi, la norme dit que “si E1 a un type signé et une valeur négative, la valeur résultante est définie par l’implémentation” , mais ce document dit que -1>>5; est un comportement non spécifié .

Donc, est -1>>5; comportement non spécifié en C? Qui est correct?

Les deux sont corrects. Le comportement défini par la mise en œuvre est un type particulier de comportement non spécifié.

Citer la section 3.4.1 de la norme C qui définit le “comportement défini par la mise en œuvre”:

1 comportement défini par la mise en œuvre

comportement non spécifié où chaque implémentation documente comment le choix est fait

2 EXEMPLE Un exemple de comportement défini par l’implémentation est la propagation du bit de poids fort lorsqu’un entier signé est décalé à droite.

À partir de la section 3.4.4, définir «comportement non spécifié»:

1 comportement non spécifié

utilisation d’une valeur non spécifiée, ou autre comportement lorsque la présente Norme internationale offre deux possibilités ou plus et n’impose aucune autre exigence sur laquelle est choisie une instance quelconque

2 EXEMPLE Un exemple de comportement non spécifié est l’ordre dans lequel les arguments d’une fonction sont évalués.

En ce qui concerne GCC, vous obtiendrez toujours la même réponse car l’opération est définie par l’implémentation. Il implémente le décalage droit des nombres négatifs via l’extension de signe

De la documentation GCC :

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

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

En tant qu’extension du langage C, GCC n’utilise pas la latitude donnée en C99 et C11 uniquement pour traiter certains aspects du << signé comme indéfini. Cependant, -fsanitize=shift (et -fsanitize=undefined ) diagnostiquera de tels cas. Ils sont également diagnostiqués lorsque des expressions constantes sont nécessaires.

“Comportement non spécifié” et “mise en œuvre définie” ne sont pas contradictoires. Cela signifie simplement que le standard C ne spécifie pas ce qui doit se passer et que diverses implémentations peuvent faire ce qu’elles jugent “correct”.

Le faire plusieurs fois sur un compilateur et obtenir le même résultat signifie seulement que ce compilateur particulier est cohérent. Vous pouvez obtenir des résultats différents sur un compilateur différent.

Le comportement défini par l’implémentation est une sousclasse de comportement non spécifié, c’est-à-dire un comportement non spécifié par la norme.

Defect Report # 154 à C89 a demandé au comité quelles sont les limites du comportement défini par la mise en œuvre ; le comité répond qu’une mise en œuvre peut définir tout comportement souhaité et que cela n’a pas besoin d’être constant.

Ce que l’implémentation doit faire, c’est documenter comment ce choix est fait, par opposition à l’autre classe de comportement non spécifié où une implémentation conforme n’a même pas besoin de dire comment le choix est fait, peut-être parce que la majorité des implémentations dirait “au hasard” ou “en fonction du niveau d’optimisation du compilateur” ou “en fonction de l’allocation du registre pour les variables locales”.

Je n’ai aucune des réponses actuelles. La norme C indique clairement que le fait de déplacer un nombre négatif est un comportement défini par la mise en œuvre . Ce n’est pas un comportement non spécifié, ce qui signifie autre chose. Comme vous le citez correctement (C17 6.5.7 §5):

Le résultat de E1 >> E2 est E1 positions de bit E2 décalées à droite. / – /
Si E1 a un type signé et une valeur négative, la valeur résultante est définie par l’implémentation.

Cela signifie que le compilateur doit documenter comment il se comporte. Période.

En pratique: le document doit indiquer si le compilateur utilise un calcul arithmétique à droite ou à droite.


Ceci s’oppose au comportement non spécifié, qui est un comportement spécifique à la mise en œuvre qui n’a pas besoin d’être documenté. Le comportement non spécifié est utilisé dans deux cas:

  • Lorsque le comportement du compilateur peut être un secret d’implémentation, le fournisseur du compilateur ne doit pas être obligé de révéler à ses concurrents.
  • Lorsque le compilateur ne peut pas être dérangé pour documenter le fonctionnement des détails sous-jacents tels que les cellules de mémoire du système d’exploitation et de la RAM.

Par exemple, un compilateur n’a pas besoin de documenter l’ordre d’évaluation dans un code comme celui-ci:

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

Documenter l’ordre dans lequel les sous-expressions sont évaluées révélerait des détails sur le fonctionnement de l’arborescence des expressions internes et de l’optimiseur du compilateur, ce qui révélerait pourquoi un compilateur produit un meilleur code ou se comstack plus rapidement que la concurrence. C’était une grande chose quand la norme C a été écrite à l’origine. Moins que de nos jours, quand il y a de bons compilateurs open-source, ce 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 valeur indéterminée et la sortie n’est pas spécifiée – en pratique, la sortie dépend de ce qui a été stocké dans cette cellule RAM particulière auparavant. Ce que nous appellerions une “valeur de déchet”. (Avant de crier “UB”, voir (Pourquoi) utilise un comportement non défini de variable non initialisée? ).