12
votes

Si des qualificateurs de type inutiles sur les types de retour soient utilisés, pour plus de clarté?

Notre outil d'analyse statique se plaint d'un "qualificatif de type inutile sur le type de retour" lorsque nous avons des prototypes dans des fichiers d'en-tête tels que:

const int foo();


2 commentaires

Cela vous dérangerait-il de partager quel outil vous utilisez? Je suis intéressé à trouver un problème similaire. Merci!


@mgouin, gardez à l'esprit que cette question a été écrite il y a environ 10 ans. ;-) Mais je pense à ce moment-là que nous utilisions la couverture. (Je ne suis pas sûr à 100%.)


6 Réponses :


5
votes

Vous pouvez utiliser une technique différente pour illustrer votre intention sans rendre les outils malheureux.

#define CONST_RETURN

CONST_RETURN int foo();


5 commentaires

Mais étant donné qu'il n'y a pas de vérification du compilateur de cette demande de const_return, n'est-ce pas préférable d'avoir un commentaire? De cette façon, au moins cela ne regarde comme quelque chose que le compilateur doit avoir vérifié.


Oui, un commentaire pourrait être encore meilleur.


Il y a quelques API / bibliothèques que j'ai vues qui ont fait quelque chose de similaire à cela. Si vous avez une fonction qui renvoie toujours le même numéro, #define foo () la valeur pourrait être le truc.


Les macros sont primitives? Oui. Les macros sont laides? Souvent. Les macros sont dangereuses? Parfois. Les macros sont mauvais? Les macros sont un outil et des outils peuvent être utilisés mal, mais je ne leur donnerais pas une condamnation de couverture.


@MarkRansom et peut-être une marque d'un véritable programmeur reçoivent les connaissances et l'expérience de savoir quand une macro est et est pas le bon outil Pour le boulot.



26
votes

Il est généralement préférable que votre code décrit aussi précisément que possible ce qui se passe. Vous obtenez cet avertissement car le const dans const int foo (); est fondamentalement sans signification. L'API ne semble plus claire si vous ne savez pas ce que le mot clé const signifie. Ne surchargez pas de sens comme ça; statique est assez mauvais tel qu'il est, et il n'y a aucune raison d'ajouter le potentiel de plus de confusion.

const char * signifie quelque chose de différent de const int < / Code> Fait, c'est pourquoi votre outil ne se plaint pas. Le premier est un pointeur sur une chaîne constante, ce qui signifie n'importe quel code appelant la fonction renvoyant que le type ne doit pas essayer de modifier le contenu de la chaîne (cela pourrait être dans la ROM par exemple). Dans ce dernier cas, le système n'a aucun moyen de faire respecter que vous n'abandonnez pas le renvoi int , de sorte que le qualificatif n'a donc pas de sens. Un plus proche parallèlement aux types de retour serait: xxx

qui provoquera la fois que votre analyse statique donne l'avertissement - l'ajout d'un qualificatif de const à une valeur de retour est une opération sans signification. Il n'a de sens que lorsque vous avez un paramètre de référence AA (ou un type de retour), comme votre const char * exemple.

En fait, je viens de faire un petit programme de test, et GCC Même explicitement avertit ce problème: xxx

Ce n'est donc pas seulement votre programme d'analyse statique qui se plaint.


7 commentaires

D'accord. Ma réaction instantanée à un type de retour const est d'assumer que le retour est une référence / un pointeur sur un tampon partagé qui ne devrait pas être changé. Mon modèle mental est que Const s'applique au conteneur (par exemple la variable), pas du contenu. Dans "const char *", par exemple, le const s'applique à la chaîne pointue, alors que si vous avez "const int i = 5;", vous pouvez toujours écrire "i + 1" dans une expression - vous pouvez travailler avec le Valeur tant que vous n'essayez pas de changer la variable. Avec un simple retour int, vous n'avez pas vraiment de conteneur - seulement une valeur.


Je suppose que les gens sont confus à cause du comportement étrange du mot clé const . Je veux dire que const char * c et chartons * c sont la même chose. Si l'ancienne syntaxe n'était pas légale, les choses seraient beaucoup moins déroutantes. Nous aurions seulement Char Const * C et Char * Cons C Et tout le monde saurait ce qui se passe. Peut-être que j'y pense trop.


D'accord, je suis convaincu. Merci d'avoir souligné l'avertissement de la GCC. J'aurais aimé que ce soit une erreur plutôt que d'un avertissement, des zones grises comme celle-ci ne se produisent pas.


Entre autres choses, const ne signifie généralement pas "cela ne va jamais changer". const signifie généralement "vous (client API) ne peut pas changer cela". La distinction est évidente lorsque vous gérez des pointeurs-to-const.


@Mike, ce n'est pas une erreur car elle ne cause aucune différence dans l'exécution du programme. La plupart des compilateurs vous permettront de transformer des avertissements en erreurs si vous le souhaitez, cependant.


@Carl: "Cons-Char * ... est un pointeur à une chaîne constante". N'est-ce pas un pointeur à un charret constant, ni alternativement, l'adresse du premier élément (constant) d'un tableau de charret / chaîne?


Oui, le const s'applique sans doute au premier caractère de la chaîne. En pratique, il est presque toujours le cas que char * pointe vers une chaîne (c Strings étant simplement des tableaux de caractères terminés nuls).



3
votes

const int foo () est très différent de const char * foo () . Const Char * FOO () renvoie un tableau (généralement une chaîne) dont le contenu n'est pas autorisé à changer. Pensez à la différence entre: xxx

et xxx

a est toujours une variable et peut être affecté à Autres cordes qui ne peuvent pas changer alors que B n'est pas une variable. Donc xxx

est autorisé mais xxx

n'est pas autorisé, même avec la déclaration const déclaration de bar () .


1 commentaires

const int b = barre () est autorisé, car vous pouvez toujours initialiser une variable const . Voulez-vous dire const int b; B = bar () ?



4
votes

Ignorer le const pour l'instant, foo () retourne une valeur. Vous pouvez faire xxx

et attribuer la valeur renvoyée par foo () à la variable x , de la même manière que vous pouvez faire xxx

pour attribuer la valeur 42 à la variable x.
Mais vous ne pouvez pas modifier le 42 ... ou la valeur renvoyée par foo () . En disant que la valeur renvoyée de foo () ne peut pas être modifiée, en appliquant le mot clé const du type de foo () n'accorde rien. < / p>

valeurs ne peut pas être const ( ou restreindre ou volatile ). Seuls les objets peuvent avoir des qualificateurs de type.


contraste avec xxx

dans ce cas, foo () retourne un pointeur sur un objet. L'objet pointé par la valeur renvoyée peut être qualifié const .


0 commentaires

3
votes

L'INT est renvoyé par copier . C'est peut-être une copie d'un const, mais lorsqu'il est affecté à autre chose, que quelque chose en vertu du fait qu'il était assignable, ne peut pas par définition être un const.

Le mot-clé Const constitue une sémantique spécifique dans la langue, alors que vous l'utilisez ici comme essentiellement un commentaire. Plutôt que d'ajouter de la clarté, cela suggère plutôt un malentendu de la sémantique du langage.


6 commentaires

Qu'est-ce que const int pi = 3.14159; int myvalue = 2 * pi; faire? Dites-vous que PI ne devrait pas être déclaré Const? Si la valeur renvoyée par la fonction ne changera pas, c'est une constante, il est donc tout à fait raisonnable de le déclarer comme tel.


@Jason: Tout à fait raisonnable mais aussi assez redondant, c'est pourquoi les outils le traitent comme un avertissement et non une erreur. Dans votre exemple, le const est pas redondant.


Ce n'est pas la même chose. Si j'ai une fonction getpi () qui vient d'avoir retour pi dedans, la valeur renvoyée n'est pas const . Il ne peut pas être const en raison des conventions sur la langue de la valeur de transmission (et de la valeur de retour).


Il n'y a pas de débat quant à savoir s'il est sémantiquement correct - même la question initiale indique clairement que ce n'est pas le cas. Mon point est que tant que le code "inutile" ne modifie pas la logique / flux du programme et ne confond pas le lecteur en attribuant une signification non conventionnelle et non intuitive à un jeton existant, je n'ai pas de problème avec une programmation équipe utilisant une telle convention. Dans ce cas (contrairement aux autres, je pouvais citer), il semble être une convention d'équipe plutôt inoffensive, qui ne confondrait pas ou induire en erreur un lecteur «externe» ne devrait-il pas l'entendre.


@Jason: Nous devrons accepter d'être en désaccord, car je crois que c'est potentiellement déroutant. Mais suggère plus sérieusement un manque d'expertise et de compréhension de l'équipe de développement. Par exemple, si, en tant que tiers, j'ai reçu ce code, cela m'inquiète de la qualité générale, car cela pourrait indiquer un manque d'expérience et une connaissance de la sémantique du langage. De votre premier commentaire, il semble que vous êtes peut-être dans une situation similaire; Parce que comme on l'a souligné, l'initialisation d'un const n'est pas la même que celle de la valeur de retour qualifiée en tant que const.


@Clifford est totalement d'accord, ses étudiants toujours qui semblent faire le retour de la valeur de Conscons lors de l'apprentissage parce qu'ils pensent en quelque sorte que c'est plus sûr ou est plus performant



2
votes

Oui. Je conseillerais d'écrire du code "explicitement", car cela indique clairement à quiconque (y compris vous-même) lors de la lecture du code ce que vous vouliez dire. Vous écrivez le code pour d'autres programmeurs à lire em>, de ne pas plaire aux caprices des outils d'analyse de compilateur et d'analyse statique!

(Cependant, vous devez faire attention à ce que tout "code inutile" ne pas causer de code différent à générer!) p>

Quelques exemples de codage explicite améliorant la lisibilité / la maintenabilité: p>

  • Je place des crochets autour des portions d'expressions arithmétiques pour spécifier explicitement ce que je veux arriver. Cela indique clairement à n'importe quel lecteur ce que je voulais dire et me sauve que vous devez vous inquiéter (ou faire des erreurs AY avec) selon les règles de priorité: P>

    virtual int MyFunc()
  • en C ++, si vous remplacez une fonction virtuelle, alors dans la classe dérivée, vous pouvez le déclarer sans mentionner "virtuel" du tout. Toute personne lisant le code ne peut pas dire que c'est une fonction virtuelle, qui peut être désastreusement trompeuse! Cependant, vous pouvez utiliser en toute sécurité le mot clé virtuel: p> xxx pré> et cela permet à quiconque lisant votre en-tête de classe que cette méthode est virtuelle. (Ce "bogue de syntaxe C ++" est fixé en C # en exigeant l'utilisation du mot-clé "Supprimer" dans ce cas - plus de preuve si quelqu'un en avait besoin qui manque au "virtuel inutile" est une très mauvaise idée) li> ul>

    Ce sont des deux exemples clairs où l'ajout de code "inutile" rendra le code plus lisible et moins sujette aux bogues. P> P>


1 commentaires

Tu ne parles pas de la même chose. Comme @PMG dit, valeurs ne peut pas être const ou quoi que ce soit d'autre. Seuls les objets peuvent. Dire qu'il est précieux de coller une étiquette const sur quelque chose qui est par définition non const est clairement une mauvaise idée. Il confond la sémantique inutilement.