6
votes

Pourquoi vous inquiéter de «comportement indéfini» dans >> de type signé?

Ma question est liée à Celui-ci et contiendra quelques questions.

Pour moi, le plus évident (signifie que je l'utiliserais dans mon code) solution au problème ci-dessus n'est que ceci: p>

uint8_t x = some value;
x = (int8_t)x >> 7;
  • Autant que je me souvienne de tout le matériel que j'avais rencontré avait des instructions distinctes pour le décalage arithmétique et logique. li>
  • Tous les compilateurs que je connais Traduire >> code> dans le décalage arithmétique pour les types signés et le décalage logique des types non signés. LI>
  • Je ne peux me souvenir d'aucun compilateur émetteur div code> d'instruction de niveau bas code> lorsque >> code> a été utilisé en code C / C ++ (et nous ne parlons pas de surcharge de l'opérateur ici ). li>
  • Tout le matériel que je connais u2. Li> ul>

    SO ... Y a-t-il quelque chose (tout compilateur contemporain, matériel) qui se comporte différemment de mentionné ci-dessus? Devrais-je simplement m'inquiéter de la valeur signée correcte non traduite en décalage arithmétique? P>

    Ma "solution" compile à une seule instruction de faible niveau sur de nombreuses plates-formes tandis que d'autres nécessitent plusieurs instructions de faible niveau. Que utiliseriez-vous dans votre code? P>

    vérité s'il vous plaît; -) p> p>


20 commentaires

Pourquoi n'aimes-tu pas ma question et tu veux fermer? Je suis vraiment intéressé par une expérience de vie réelle des autres sur diverses plateformes et avec des compilateurs que je n'ai pas utilisés.


Selon C11 (§6.5.7 P 5) en utilisant des types signés dans un changement de droite n'est pas non défini mais comportement défini sur la mise en œuvre .


Je ne reçois pas ce que vous n'obtenez pas dans indéfini comme dans le comportement non défini. Votre PC pourrait sauter et prendre feu, et vous pourriez obtenir des démons nasaux. Si votre compilateur garantit quelque chose, vous pouvez compter sur cela, mais uniquement sur ce compilateur particulier .


Vous avez tort de penser que le compilateur traduit les instructions une par une. Le compilateur considère le programme entiers et compile / l'optimise dans son ensemble. Lecture nécessaire: [1 ] , [2 ], < un href = "http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_21.html" rel = "nofollow noreferrer"> [3 ].


@Vlad: Je suis vraiment conscient de cela.


@ARTUR: Mais vous dites "Compilateurs que je connais Traduire >> en équipe arithmétique". Cela implique la réflexion en termes d'opérations, pas de l'ensemble du programme.


Ajout au commentaire de @ Kninnug, C ++ 11 dit la même chose: E1 >> E2 "Si E1 a un type signé et une valeur négative, la valeur résultante est la mise en œuvre. défini. "


@HVD: Je sais quelle standard dit à propos de la droite sur la signature et c'est pourquoi je mentionne un Bahavior non défini dans ma question.


@ARTUR Je ne pense pas que tu fais. Mon point et Kninnug's, c'est qu'il n'y a pas de comportement indéfini lorsque vous changez de droit à droite un entier négatif, donc si vous comprenez cela, pourquoi mentionnez-vous un comportement indéfini? :)


@ARTUR Ce n'est pas un cas de comportement non défini - il est spécifié de la mise en œuvre. -1 >> 3 est une expression valide: elle évaluera à une valeur entière par opposition à la production de démons nasaux.


La fermeture de cette question comme base d'opinion est une sauce faible. Il y a des raisons légitimes de ne pas écrire du code qui expose UB et la clôture de cette question pour cette raison ne fait que valider l'opinion de l'OP que "un comportement non défini" est surutilisé pour justifier une question de savoir si la question est étiquetée C / C ++. " Cela ne l'aide pas ou personne d'autre à écrire un meilleur code.


À tout le moins, "Alors ... y a-t-il quelque chose (tout compilateur contemporain, matériel) qui se comporte différemment de mentionné ci-dessus?" est une question pour les faits difficiles, pas les opinions.


C'est une question d'enquête, et tels sont typiquement considérés comme étant hors sujet. Je trouve peu probable que toute personne puisse répondre au comportement de tous les compilateurs sur toutes les plateformes. De manière réaliste, les réponses seront limitées à un sous-ensemble d'implémentations que le répondeur estime être importante.


C'est vrai. D'autre part, si un tel système existe, une réponse correcte ne s'appuie pas sur une personne qui répondait également à tous les autres systèmes.


@HVD alors la question devrait probablement être reformulée comme «Est-ce que quelqu'un connaît une implémentation C ++ qui ne met pas en œuvre le passage de la valeur négative de la valeur négative en tant que préservation de la signalisation?»


@Casey: Je peux répondre à cette question. Tout Le comportement indéfini est par définition impossible à prouver correctement dans le contexte de conformité aux normes C ++. Le fait que certains codes particuliers soient destinés à une pile matérielle spécifique ne sont pas pertinents.


@JohndiBibling Il n'y a pas de comportement indéfini ici.


@Casey: La question concerne l'UB, pas un petit extrait de code spécifique.


@Case c'est comme ça que je lis déjà cette question. :) En fait, pensez-y, l'une de ces implémentations rares mais existantes qui n'utilisent pas le complément de deux personnes sont probablement suffisantes en tant que contre-exemple aux fins de l'OP. La question suivante: «D'accord ... mais que diriez-vous des implémentations qui comptent réellement?», Serait certainement basé sur l'opinion.


Le seul compilateur C J'ai jamais utilisé qui ne signer pas-étendre à droite est le compilateur MCC18 Pics de Microchip (en général si vous recherchez une sémantique bizarre C, puis cherchez des microcontrôleurs, des DSP et des ordinateurs centraux). Cela m'a mordu dans le code réel porté à partir d'autres systèmes. Incidemment, cela fait également des divisions signées au lieu de zéro.


3 Réponses :


9
votes

Pourquoi vous inquiétez-vous de «comportement indéfini» dans >> de type signé?

Parce que cela n'a pas vraiment d'importance à quel point le comportement non défini est bien défini est maintenant ; Le but est que cela peut casser à tout moment à l'avenir. Vous comptez sur un effet secondaire qui peut être optimisé (ou non optimisé) à tout moment pour une raison quelconque ou aucune raison.

En outre, je ne veux pas avoir à demander à quelqu'un une connaissance détaillée de nombreuses implémentations de Compiler avant d'utiliser quelque chose que je ne devrais pas utiliser en premier lieu, alors je le saute.


10 commentaires

Pour compléter ce que @meagar a dit à propos de l'avenir, vous utilisez 4 au lieu de Tailleof (int) car c'est plus facile, puis vient des ordinateurs 64 bits et mordez votre A * S


@ Fernando.reyes: Ce n'est pas la même chose. Je pense que mon problème me manque. Je ne pense pas que je me réveillerai jamais et que les compilateurs traduiront >> dans qc. différent de changer.


@ARTUR Comme vous l'avez dit "Tous les compilateurs que je connais Traduire ...", vous base de l'hypothèse indéfinie-comportement - sans importance dans l'état actuel des compilateurs que vous connaissez, mais que vous puissiez un futur compilateur ou celui que vous ne savez pas de traiter il différemment et il sera indéfini


@ARTUR: En fait, tout compilateur décent traduit 2 >> 1 dans une constante 1, donc pas de changement de niveau d'assembleur.


@ARTUR Si nous avons manqué votre point, c'est parce que votre question n'était pas claire. Vous avez demandé à "Pourquoi vous inquiétez-vous du comportement non défini", non "Pensez-vous que cela deviendra un comportement défini".


@Vlad: Vous pouvez penser à beaucoup d'autres cas où >> ne comporteront tout simplement pas du tout. Je suis au courant du pliage constant, etc.


@meagar: Mon mauvais. En effet, j'aurais peut-être dû demander s'il est sûr, etc. et si quelqu'un l'utiliserait en dehors de moi. Merci quand même. Je pensais juste que ma question sera très évité mais ne confirme tout simplement pas que je suis juste à propos de la descente de la question était fermée ;-)


Bien sûr, certains comportements non définis non définis ou non définis par la mise en œuvre sont lourds conformément à, donc en pratique, c'est un compromis entre le temps de développement et la portabilité. Ne pas avoir à s'inquiéter des entiers de 16 bits est une commodité qui vaut simplement la peine pour certains projets, et je pense que nous pouvons tous convenir de supposer plus de 6 caractères uniques insensibles de cas dans des noms externes du code C89.


@ARTUR: Encore une fois, cela implique le modèle mental "Compilation de déclaration par déclaration avec des optimisations très locales", ce qui n'est bien sûr pas vrai. Mon point est que vous ne pouvez jamais prédire que le code va être produit par compilateur, donc l'idée ">> est une équipe de décalage ou de compilation" ne reflète pas la vérité.


@Vlad: convenu. Le problème est que de nombreuses solutions sont créées «type de laid / compliqué» dans le seul but d'éviter les banaviors non définis. Je sais que la compilation est proche de - comme vous l'avez dit - "Déclaration par déclaration" en mode de débogage, mais lors de l'optimisation de diverses techniques. Le problème est que les compilateurs ne sont pas souvent si intelligents et c'est ce que je m'inquiète. Si vous utilisez Par exemple, utilisez XOR pour une swap de valeur (au lieu d'échanger avec TEMP), vous supposez que 1) Les lecteurs sauront que vous swap 2) Compiler peut figurer cela et optimiser et non seulement traduire une ligne par ligne. J'espère que vous savez maintenant ce que je veux dire.



2
votes

Oui, il y a des compilateurs qui se comportent différents de ce que vous supposez.

En particulier, des phases d'optimisation dans les compilateurs. Ceux-ci tirent parti des valeurs possibles connues des variables et dérivent ces valeurs possibles de l'absence de UB. Un pointeur doit être non nul s'il a été déréférencé, un entier doit être non nul s'il a été utilisé comme diviseur et une valeur décalée droite doit être non négative.

et cela revient À temps: xxx


2 commentaires

Les changements de droite signés et la division entière signée (en C89, pas de C99 ou C11) sont définis par la mise en œuvre, pas un comportement non défini. Sur la grande majorité des compilateurs actuels spécifiant le changement de droite arithmétique, cela fonctionne très bien.


@Doynax: Pour moi, cela ressemble seulement à vous avoir compris ma question. Merci.



0
votes

Qu'est-ce qui va vraiment, est-ce que vous êtes prêt à prendre le risque?

"La norme ne garantit pas Yada Yada" est belle et toutes, mais soyons honnêtes maintenant, le risque n'est pas grand. Si vous allez exécuter votre code sur une plate-forme folle, vous savez généralement à l'avance. Et si cela vous prend par surprise, eh bien, c'est le risque que vous avez pris.

En outre, la solution de contournement est horrible. Si vous n'allez pas en avoir besoin, il suffit de polluer votre code de code avec des appels de fonction inutiles à la place des droits de droite »qui seront plus difficiles à maintenir (et à porter ainsi un coût). Et vous ne pourrez jamais "coller et oublier" le code d'autres endroits dans le projet - vous devez toujours vérifier le code de la possibilité de changer les entiers signés négatifs.


1 commentaires

Le fait que le changement de vitesse soit la mise en œuvre plutôt que non définie sert de vérification critique dans la capacité des écrivains obtus compilateurs à désordre avec le code qui repose sur le comportement. Sur une plate-forme avec 16/32 bits courts / int, il n'y a aucune raison uint1 = uhort1 * uhort2; ne devrait pas donner des résultats arithmétiquement-correct 100% du temps pour toutes les combinaisons d'opérande, mais sur GCC ça ne le fait pas.