GCC doit émettre des warnings pour des usages de l'opérateur xor comme 2^16, 2^32, 2^64 qui prêtent à confusion,
D'après des utilisateurs

Le , par Patrick Ruiz

176PARTAGES

19  0 
Dans bon nombre de langages de programmation dont le C et le C++, l’opérateur ^ ne fait pas référence à celui d’exponentiation, mais au OU exclusif. Il vient alors qu’après évaluation, une expression comme 2^16 donne non pas 65 536, mais 18. Des exemples d’utilisation de cet opérateur foisonnent sur la toile et certains peuvent prêter à confusion pour qui lit (ou écrit) du code.

Code C : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
tp->tv_sec  = attributes[0] / 10^9;
tp->tv_nsec = attributes[0] % 10^9;
 
range->pmin[TREND_FCT] = -10^10;
range->pmax[TREND_MEAN] = 10^10;
 
#define IRQ_CHINT5_LEVEL        (12 ^ 7)
#define IRQ_CHINT4_LEVEL        (11 ^ 7)
#define IRQ_CHINT3_LEVEL        (10 ^ 7)
#define IRQ_CHINT2_LEVEL        (9 ^ 7)
#define IRQ_CHINT1_LEVEL        (8 ^ 7)


Code C : Sélectionner tout
1
2
3
4
5
read_bytes(&f, (char *) &(val),
                   ( (n < (2 ^ 8))  ? 1 :
                     ( (n < (2 ^ 16)) ? 2 :
                       ( (n < (2 ^ 24)) ? 3 :
                         4 ) ) ) );

« GCC n’émet pas d’avertissement pour : short maxshort = 2^16;, int maxint = 2^32; long maxlong = 2^64; Il faut que ce soit le cas en C et en C++. Je ne vois pas de raison valable d'écrire 2^16 quand vous voulez dire 18 ou 10^9 quand vous voulez dire 3, donc c'est probablement un bogue », a lancé Jonathan Wakely sur la liste de diffusion de bugs de GCC. « Mon Dieu que de faussetés en une seule ligne de code », a réagi un internaute sur un tweet d’un des participants aux échanges sur la liste de diffusion dédiée à GCC. En fait, l’un des problèmes avec cette ligne de code est qu’étant donné que l’expression 2^32 est évaluée en considérant l’opérateur ^ comme un OU exclusif, il vient que la boucle n’aura pas le nombre d’itérations auquel le rédacteur du code s’attend.


Si des tiers ont beaucoup plus remonté les cas d’ambiguïté qui se posent avec ce qui s’apparente de prime abord à des exponentiations de base 2, il faut dire que le problème reste le même avec les autres bases. Cet état de choses complexifie la détermination de l’angle sous lequel l’avertissement à générer sous GCC doit être orienté.

« Je pense que les avertissements doivent porter sur les cas où les deux opérandes sont des nombres entiers. Seulement, peut-on traiter tous les entiers sur un pied d’égalité ? Est-ce que 0x11 ^ 0b0011 est faux ? En tout cas, ça ne l’est pas de façon aussi évidente que 2^8 et 2^32. Est-ce que ces erreurs n'arrivent qu'aux puissances de 2 et 10 ? Est-ce que ça vaut la peine d'avertir à propos de 3^4 ? Après d'autres recherches, je ne suis même pas sûr que 10^ soit assez commun pour m'inquiéter. Peut-être que le compilateur ne devrait générer un avertissement que pour les cas qui s’apparentent à une exponentiation de base 2. Amener GCC à générer un avertissement pour ces situations que l’on pourrait considéré comme une exponentiation dans laquelle la base et l’exposant sont égaux semble également faire sens. Cela pourrait permettre de mettre la main sur des cas comme 10^10, mais pas sur 10^10 », a ajouté Jonathan Wakely.

Les discussions battent leur plein sur la liste de diffusion GCC. Quelque soit le consensus sur lequel elles vont déboucher, il ne faut pas perdre de vue qu’il s’agit seulement d’étendre les capacités du compilateur générer des avertissements pour des cas de figure précis. En général, les compilateurs sont dotés d’options d’activation ou de désactivation des avertissements, ce qui fait que l’utilisateur n’est pas dans l’obligation de subir un en particulier.

Source : liste de diffusion GCC

Et vous ?

Qu’en pensez-vous ?
Êtes-vous en accord avec la nécessité que GCC génère ce warning ? Si oui, quels sont d’après vous les axes les plus pertinents ?
En tombant sur une ligne de code C comme for (int i = 0 ; i < = ( 2^32)1 ; i++) {} avez-vous au premier regard le sentiment qu’il y a une erreur qui s’est glissée ?

Voir aussi :

La version 9.1 du compilateur GCC est disponible et prend en charge le C++17, plusieurs autres fonctionnalités sont ajoutées

GCC 9 sera la première version stable du compilateur à supporter le langage D, un nouveau front-end allonge la liste

GCC 8.1 est disponible, la nouvelle version majeure du compilateur libre vient avec un support expérimental de C++2a et d'autres fonctionnalités

GCC 8.2 est disponible. Cette mise à jour du compilateur libre corrige une centaine de bogues

GCC : la version 7.3 du compilateur libre est disponible avec des correctifs pour la vulnérabilité Spectre pour les dispositifs x86 et powerpc

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de TheLastShot
Membre extrêmement actif https://www.developpez.com
Le 18/06/2019 à 20:30
Et l'opérateur | est utilisé pour le "ou binaire" alors qu'en ligne de commande il sert de "pipe" pour chaîner les instructions... Il y a aussi le "%" qui est utilisé pour faire un modulo au lieu de calculer un pourcentage.... Il va lancer une alerte sur tous les opérateurs qui ne correspondent pas l'usage auquel il s'attend ?
Quand on connait le langage, ça ne prête absolument pas à confusion, sinon c'est qu'on connait pas le langage et en particulier ses opérateurs de base...
3  0 
Avatar de SimonDecoline
Membre expert https://www.developpez.com
Le 18/06/2019 à 22:14
Citation Envoyé par Patrick Ruiz Voir le message
Dans bon nombre de langages de programmation dont le C et le C++, l’opérateur ^ ne fait pas référence à celui d’exponentiation, mais au OU exclusif
...
peuvent prêter à confusion
...
Je suis d'accord, d'autant plus dans des projets qui utilisent plusieurs langages. Mais il existe déjà une solution : https://en.cppreference.com/w/cpp/la...or_alternative. Perso, j'ai quasiment banni && || ! de mes codes au profit de and or not.
3  0 
Avatar de lsbkf
Membre habitué https://www.developpez.com
Le 19/06/2019 à 1:12
Quand on fait du C, on part déjà du principe qu'on est dans un langage bas niveau et que l'exponentiation n'est pas une opération élémentaire. Même pour la division et le modulo, qui sont beaucoup plus courants, je connais des gens qui militent contre leur utilisation, surtout si le diviseur est une variable ou que c'est compilé pour du ARM.

Je pense que les gens qui font cette erreur ont raté leur vocation ou n'en ont rien à foutre. Ce n'est pas le seul langage à utiliser ^ pour le XOR, ce n'est pas le seul opérateur qui a des significations différentes sur des langages différents, il y a aussi des fonctions qui ne donnent pas le même résultat partout, et même les mot-clés ne sont pas à l'abri.
2  0 
Avatar de transgohan
Expert éminent https://www.developpez.com
Le 19/06/2019 à 8:50
Êtes-vous en accord avec la nécessité que GCC génère ce warning ? Si oui, quels sont d’après vous les axes les plus pertinents ?
Comme d'autres intervenants je ne trouve pas que cela soit nécessaire.
Si on fait le parallèle avec une fonction qu'on appellerai add() et qui permettrai d'ajouter un élément dans un tableau on pourrait très bien imaginer dans un langage qu'elle l'ajoute en début et dans un autre à la fin...
Dans tout langage il faut connaître les fonctions et leur fonctionnement.
Le xor est une fonction.

Précisons que Jonathan Wakely est un membre émérite de la team GCC ainsi que du comité de normalisation C++, contributeur très respecté de Stack overflow : il convient de réfléchir à deux fois avant de balayer ses propos d'un revers de main
C'est pourtant ce que je fais, sans être un membre émérite de quoi que ce soit.
Car ma pensée me semble logique, davantage que la sienne.
Il voit un bug là où je ne vois qu'une personne qui ne connait pas la norme du langage (j'exagère bien sûr car je me doute qu'il la connait davantage que moi).
Le compilateur est là pour valider qu'on applique la norme. Pas pour deviner ce que l'on voulait écrire.
2  0 
Avatar de walfrat
Membre habitué https://www.developpez.com
Le 19/06/2019 à 9:00
Je suis contre.

Pour peu qu'on suive ne serait-ce qu'un tuto de base sur le net pour apprendre le langage, on apprend les opérateurs, opérateurs qui ont tendance à être les même dans beaucoup de langages puisqu'ils s'inspirent les un des autres..

Si des personnes qui n'ont pas les bases se retrouve à faire du C/C++ et qu'ils ne testent pas le bon fonctionnement de leur code (ben oui si tu test, ça se voit que ça marche pas), c'est pas la faute de GCC.
2  0 
Avatar de Aurelien.Regat-Barrel
Expert éminent sénior https://www.developpez.com
Le 19/06/2019 à 11:43
Mon Dieu, que d'exemples de réactions typiques de la culture du mépris Avec ce type de raisonnement on serait resté à l'assembleur (von Newmann considérait que ceux qui codaient en FORTRAN plutôt qu'en assembleur étaient des imbéciles qui n'avaient rien à faire en informatique).

Le point soulevé est pourtant simple : quel intérêt d'écrire 2^16 quand on a besoin de la valeur 18? Il ne s'agit pas de bannir l'utilisation du XOR, il s'agit d’émettre un warning dans des cas d'utilisation louches. Où est le problème ? GCC émet déjà tout un tas de warnings du genre, comme par exemple:

Code : Sélectionner tout
1
2
3
4
5
void f(int x) {
    if (x < 0)
        printf("fixing negative value\n");
        x = 0;
}
In function 'void f(int)':
<source>:4:5: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
if (x < 0)
^~
<source>:6:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
x = 0;
^
Dire "ceux qui écrivent ça sont des gros nazes qui ne devraient pas coder en C" n'est pas une réponse satisfaisante pour ceux qui sont victimes des bugs. Que faites vous, en tant que professionnels de l'informatique, pour améliorer la qualité des outils que vous utilisez afin qu'ils soient plus sûr à l'usage ? j'explique qu'il n'y a que les gens aussi brillants que moi qui devraient les utiliser et que les autres imbéciles devraient aller voir ailleurs

Citation Envoyé par transgohan Voir le message
Car ma pensée me semble logique, davantage que la sienne. [...] Le compilateur est là pour valider qu'on applique la norme. Pas pour deviner ce que l'on voulait écrire.
Et bien il est temps de réaliser que ce n'est plus ce qu'on attend d'un compilateur aujourd'hui. Il suffit de regarder les évolutions de gcc de la version 4 à la dernière pour voir la transformation en terme d'analyse et de remontée d'erreurs / warnings. Et d'autres langages comme Rust poussent plus loin la logique en fusionnant carrément l'analyseur statique avec le compilateur. Evoluer ou disparaître...

Ma remarque sur Jonathan Wakely porte sur le fait que ça fait plus de 10 ans qu'il travaille sur l'évolution du langage : soumettre une proposition de changement, argumenter de son utilité auprès des autres membres du comité, intégrer les remarques et objections, modifier le texte de la norme en conséquences, et finalement implémenter le changement dans GCC. Précisons aussi que son boulot consiste finalement à améliorer la plateforme RedHat. Et intercepter toujours plus de bugs idiots dans GCC est une réelle réponse face aux problèmes rencontrés à cause des multiples composants tiers bugués qui y sont intégrés : c'est ce qui permet de rendre la plateforme plus safe au fil du temps.

Donc quand ce genre de personne propose un changement dans le langage, en général, il y a une certaine idée derrière qu'il faut prendre le temps de comprendre. Sinon c'est un peu comme le mec du club de boxe du coin qui, quand il entend Mike Tyson expliquer que c'est normal d'avoir quand on monte sur le ring, répond que c'est n'importe quoi, que les vrais mecs n'ont pas peur, les véritables boxeurs comme lui ne craignent pas de monter sur le ring... Oui oui c'est ça c'est bien, tu as raison mon grand...
2  1 
Avatar de transgohan
Expert éminent https://www.developpez.com
Le 19/06/2019 à 13:46
Citation Envoyé par Aurelien.Regat-Barrel Voir le message
Mon Dieu, que d'exemples de réactions typiques de la culture du mépris
[...]
Donc quand ce genre de personne propose un changement dans le langage, en général, il y a une certaine idée derrière qu'il faut prendre le temps de comprendre.
Quand on parle de culture du mépris...
On a tout à fait le droit de ne pas être d'accord avec ce monsieur, et ce peu importe sa pensée.
Cela ne fait pas de nous des abrutis...
A bon entendeur.
2  0 
Avatar de stardeath
Membre expert https://www.developpez.com
Le 19/06/2019 à 17:40
Citation Envoyé par Aurelien.Regat-Barrel Voir le message
Le point soulevé est pourtant simple : quel intérêt d'écrire 2^16 quand on a besoin de la valeur 18? Il ne s'agit pas de bannir l'utilisation du XOR, il s'agit d’émettre un warning dans des cas d'utilisation louches. Où est le problème ? GCC émet déjà tout un tas de warnings du genre, comme par exemple:
l'intérêt? le même que quand tu écris 1<<3 à la place de 8 ou 0xdeadbeef à la place de 3735928559, parce que dans le contexte d'écriture de ces morceaux de code, tu identifies plus facilement les erreurs avec 1<<3 ou 0xdeadbeef qu'avec 8 et 3735928559.
un code dépend toujours minimum d'un contexte, et ça, un compilateur, comme le mentionne d'autres personnes, n'a pas la conscience des ces contextes, il n'est pas dans la tête des gens.
donc mettre un warning comme ton exemple avec un if sans accolade et un code trop indenté, pourquoi pas, autant là mettre un warning pour dire que dans certains cas "attention cet opérateur ^ à cet endroit n'est pas la mise à la puissance" me semble contre productif.

le problème avec la multiplication de ces warnings, c'est la multiplication des faux-positifs ou pire des lignes de commandes à rallonge pour désactiver tous les warnings, et je trouve que c'est un problème pire que celui soulevé dans ce fil.
pour ajouter à ça, les warnings c'est spécifiques au compilo, et écrire du code correct (point de vu norme) est déjà pas simple, si en plus tu dois avoir un code sans warning et multi plateforme, bonjour la cata.

après un autre problème, quand tu cites le palmarès de ce monsieur, ça s'appelle un argument d'autorité, et vu ce qui est sortie du comité c++ comme incohérences ces dernières années (incohérences critiquées même par d'autres sommités genre Sutter ou Stroustrup, j'en parle dans d'autres fils, je vais pas me répéter ici), il serait plutôt bon de les challenger, ceux qui vont devoir subir ce qu'ils décident, c'est nous, pas eux.
2  0 
Avatar de Pyramidev
Expert confirmé https://www.developpez.com
Le 20/06/2019 à 17:39
Citation Envoyé par AoCannaille Voir le message
j'ai croisé une surcharge de operator(), tout ça pour économiser un getter... L'appel ressemble à un constructeur, c'est assez troublant, mais même ça au final, est-ce que ça mérite un warning?
Quand une classe n'a qu'une seule opération importante, c'est normal de surcharger operator(). Il faut cependant veiller à ce que le nom de la classe soit suffisamment clair pour que l'on sache ce que fera operator().

Quand on utilise <algorithm> de la bibliothèque standard, quand on veut personnaliser un prédicat ou un critère de comparaison, on passe souvent par une classe qui surcharge operator().

Quand on veut mettre un objet dans un std::function, il faut que l'objet appartienne à une classe qui surcharge operator().
2  0 
Avatar de AoCannaille
Membre émérite https://www.developpez.com
Le 18/06/2019 à 18:29
Qu’en pensez-vous ?
Êtes-vous en accord avec la nécessité que GCC génère ce warning ? Si oui, quels sont d’après vous les axes les plus pertinents ?
J'en pense qu'il y a des erreurs plus courantes à améliorer dans gcc avant celle là que je n'ai jamais rencontré encore.
Je pense en particulier au fait de déclarer une fonction avec un type de retour, mais sans le mot clef return. Ceci ne génère qu'un warning et pas une erreur de compilation, c'est parfaitement stupide...
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
int superFonction(int& superArgument)
{
    superArgument++,
}
 
int main(int argc, char ** argv)
{
    int i = 0;
    printf("be amazed: %d", superFonction(i));
 
    return 0;
}
Cela va afficher ce qu'il y avait en mémoire dans l'emplacement mémoire prévue pour la variable retournée dans la fonction. Emplacement non initialisé (sauf en débug) qui va donc générer des cas incohérents en release...

Je ne comprend pas pourquoi cela existe encore, on a un mot clef clair quand on ne veut pas de return dans notre fonction : void. Ils devraient l'utiliser

En tombant sur une ligne de code C comme for (int i = 0 ; i < = ( 2^32)1 ; i++) {} avez-vous au premier regard le sentiment qu’il y a une erreur qui s’est glissée ?
Je ne suis jamais tombé sur ce cas, peut être que je ne code pas assez bas niveau pour m'amuser avec les masques de bits.
En tout cas, comme je n'ai pas l'habitude de voir de '^', je me serai posé la question. Sans remettre en cause le code, je serai allé vérifié ça sur le net ou en local sur un projet type hello world.
1  0 
Contacter le responsable de la rubrique C++

Partenaire : Hébergement Web