Si des qualificatifs de type inutiles sur les types de retour être utilisés, pour plus de clarté?

StackOverflow https://stackoverflow.com/questions/1579435

Question

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

const int foo();

Nous avons défini de cette façon parce que la fonction retourne une constante qui ne changera jamais, pensant que l'API semblait plus claire avec const en place.

Je me sens comme cela est similaire à des variables globales explicitement initialise à zéro pour plus de clarté, même si la norme C indique déjà que tous les GLOBALS seront initialisées à zéro sinon explicitement initialisé. A la fin de la journée, il n'a pas d'importance. (Mais l'outil d'analyse statique ne se plaint pas à ce sujet.)

Ma question est, est-il une raison que cela pourrait poser un problème? Faut-il ignorer les erreurs générées par l'outil, ou devrions-nous amadouer l'outil au coût éventuel d'une API moins claire et cohérente? (Il retourne d'autres constantes de const char* que l'outil n'a pas de problème avec.)

Était-ce utile?

La solution

Il est généralement préférable pour votre code pour décrire aussi précisément que possible ce qui se passe. Vous obtenez cet avertissement parce que le const dans const int foo(); est essentiellement vide de sens. L'API ne semble plus claire si vous ne savez pas ce que signifie le mot-clé const. Ne surchargez pas un sens comme ça; static est assez mauvais comme 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 que const int ne, qui est la raison pour laquelle votre outil ne se plaint pas. Le premier est un pointeur vers une chaîne constante, ce qui signifie tout code appelant la fonction de retour ce type ne devrait pas essayer de modifier le contenu de la chaîne (il pourrait être dans la ROM par exemple). Dans ce dernier cas, le système n'a aucun moyen de faire respecter que vous faites pas de modifications à la int de retour, de sorte que le qualificatif est dénué de sens. Un examen plus parallèle aux types de retour serait:

const int foo();
char * const foo2();

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

En fait, je viens de faire un petit programme de test, et GCC même met explicitement en garde sur ce problème:

test.c:6: warning: type qualifiers ignored on function return type

Il est donc pas seulement votre programme d'analyse statique qui plaindrait.

Autres conseils

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

#define CONST_RETURN

CONST_RETURN int foo();

Vous ne disposez pas d'un problème avec const char * parce que ce déclarant un pointeur à caractères constant, pas un pointeur constant.

Ignorant la const pour l'instant, foo() retourne une valeur. Vous pouvez faire

int x = foo();

et affecter la valeur retournée par foo() à la x variable de la même façon que vous pouvez faire

int x = 42;

pour affecter la valeur 42 à la variable x.
Mais vous ne pouvez pas changer le 42 ... ou la valeur retournée par foo(). Dire que la valeur retournée par foo() ne peut pas être modifié, en appliquant le mot-clé const au type de foo() accomplit rien.

Valeurs ne peuvent pas être const ( ou restrict, ou volatile ). Seuls les objets peuvent avoir des qualifications de type.


Contraste avec

const char *foo();

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

Le int est renvoyé par Copier . Il est peut-être une copie d'un const, mais quand il est affecté à quelque chose d'autre, que quelque chose en vertu du fait qu'il était cessible, ne peut pas, par définition, être un const.

Le mot clé const a une sémantique spécifique dans la langue, alors qu'ici vous abusez comme essentiellement un commentaire. Plutôt que d'ajouter la clarté, il suggère plutôt une mauvaise compréhension de la sémantique du langage.

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

 const char* a = "Hello World";

et

const int b = 1;

a est encore une variable et peut être affecté à d'autres chaînes qui ne peuvent pas changer alors b n'est pas une variable. Donc,

const char* foo();
const char* a = "Hello World\n";
a = foo();

est autorisé mais

const int bar();
const int b = 0;
b = bar();

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

Oui. Je vous conseille d'écrire du code « explicitement », parce qu'il montre clairement à tout le monde (y compris vous) lors de la lecture du code que vous vouliez dire. Vous écrivez du code pour autres programmeurs à lire , non pour plaire aux caprices du compilateur et des outils d'analyse statique!

(Cependant, vous ne devez veiller à ce que toute « code inutile » ne provoque pas de code différent à générer!)

Quelques exemples de codage explicite améliorer la lisibilité / maintenabilité:

  • Je place des crochets autour de parties d'expressions arithmétiques pour spécifier explicitement ce que je veux arriver. Cela rend clair pour tout lecteur ce que je voulais dire, et me évite d'avoir à vous soucier (ou faire des erreurs avec ay) règles de priorité:

    int a = b + c * d / e + f;      // Hard to read- need to know precedence
    int a = b + ((c * d) / e) + f;  // Easy to read- clear explicit calculations
    

  • En C ++, si vous remplacez une fonction virtuelle, puis dans la classe dérivée, vous pouvez le déclarer sans mentionner « virtuel » du tout. Toute personne qui lit le code ne peut pas dire que c'est une fonction virtuelle, qui peut être désastreusement induire en erreur! Cependant, vous pouvez utiliser en toute sécurité le mot-clé virtuel:

    virtual int MyFunc()
    et cela montre clairement à tout le monde la lecture de votre tête de classe que cette méthode est virtuelle. (Ce « C ++ bogue de syntaxe » est fixée en C # en exigeant l'utilisation du mot-clé « prioritaire » dans ce cas - plus la preuve si quelqu'un avait besoin qui manque le est une très mauvaise idée « virtuelle inutile »)

Ce sont deux exemples clairs où l'ajout de code « inutile » va rendre le code plus lisible et moins sujettes à des bogues.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top