Question

Je voudrais voir tous les endroits dans mon code (C ++) qui valeur ne tenez pas compte de retour d'une fonction. Comment puis-je le faire - avec gcc ou un outil d'analyse de code statique

?

Mauvais exemple de code:

int f(int z) {
    return z + (z*2) + z/3 + z*z + 23;
}


int main()
{
  int i = 7;
  f(i); ///// <<----- here I disregard the return value

  return 1;
}

S'il vous plaît noter que:

  • il devrait fonctionner même si la fonction et son utilisation sont dans des fichiers différents
  • libre outil de vérification statique
Était-ce utile?

La solution

Vous voulez l'attribut warn_unused_result de GCC:

#define WARN_UNUSED __attribute__((warn_unused_result))

int WARN_UNUSED f(int z) {
    return z + (z*2) + z/3 + z*z + 23;
}

int main()
{
  int i = 7;
  f(i); ///// <<----- here i disregard the return value
  return 1;
}

Essayer de compiler ce code produit:

$ gcc test.c
test.c: In function `main':
test.c:16: warning: ignoring return value of `f', declared with
attribute warn_unused_result

Vous pouvez le voir en cours d'utilisation dans le noyau Linux ; ils ont une macro __must_check qui fait la même chose; semble que vous avez besoin de GCC 3.4 ou plus pour que cela fonctionne. Ensuite, vous trouverez que macro utilisé dans les fichiers d'en-tête du noyau:

unsigned long __must_check copy_to_user(void __user *to,
                                        const void *from, unsigned long n);

Autres conseils

Pour autant que je sache il n'y a pas d'option de GCC pour donner cet avertissement. Toutefois, si vous êtes intéressé par des fonctions spécifiques, vous pouvez les marquer avec un attribut:

int fn() __attribute__((warn_unused_result));

qui donnerait un avertissement si n'a pas été utilisé la valeur de retour de fn (). Caveat: Je ne l'ai jamais utilisé cette fonction moi-même

.

Vous pouvez utiliser ce modèle pratique pour le faire lors de l'exécution.

Au lieu de retourner un code d'erreur (par exemple HRESULT) vous retournez un code_retour , qui affirme si elle est hors de portée sans la valeur en cours de lecture. Ce n'est pas un outil d'analyse statique, mais il est pas moins utile.

class return_value
{
public:
  explicit return_value(T value)
    :value(value), checked(false)
  {
  }

  return_value(const return_value& other)
    :value(other.value), checked(other.checked)
  {
    other.checked = true;
  }

  return_value& operator=(const return_value& other)
  {
    if( this != &other ) 
    {
      assert(checked);
      value = other.value;
      checked = other.checked;
      other.checked = true;
    }
  }

  ~return_value(const return_value& other)
  {
    assert(checked);
  }

  T get_value()const {
    checked = true;
    return value;
  }

private:
  mutable bool checked;
  T value;
};

Pour 17 C ++ la réponse à cette question change puisque nous avons maintenant le [[nodiscard]] attribut. Couvert [dcl.attr.nodiscard] :

  

Le nodiscard attribut-jeton peut être appliqué à l'déclarateur-id dans une déclaration de fonction ou à la déclaration d'une classe ou une énumération. Elle est assurée au plus une fois dans chaque liste d'attributs et aucun attribut argument article est présente.

et

  

[Exemple:

struct [[nodiscard]] error_info { /* ... */ };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
  enable_missile_safety_mode(); // warning encouraged
  launch_missiles();
}
error_info &foo();
void f() { foo(); }             // warning not encouraged: not a nodiscard call, because neither
                                // the (reference) return type nor the function is declared nodiscard
     

- exemple final]

modifier votre exemple ( voir vivre ):

[[nodiscard]] int f(int z) {
    return z + (z*2) + z/3 + z*z + 23;
}


int main()
{
  int i = 7;
  f(i); // now we obtain a diagnostic

  return 1;
}

Nous obtenons maintenant un diagnostic avec gcc et Clang par exemple.

warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]
  f(i); // now we obtain a diagnostic
  ^ ~

Tout code d'analyse statique (par exemple PC-Lint ) devrait être en mesure de vous dire que. Pour PC-Lint, je sais que cela est le cas.

un analyseur statique fera le travail pour vous, mais si votre base de code est alors plus trivial préparer à être submergés; -)

Un analyseur statique sera votre meilleur pari ici. Nous utilisons Coverity, mais il y a outils gratuits disponibles que vous pouvez utiliser aussi bien.

Si vous avez besoin d'une solution rapide et sale et vous avez un style shell Linux à portée de main, vous pouvez essayer quelque chose comme:

grep -rn "function_name" * | grep -v "="

Ce trouvera chaque ligne qui fait référence à la fonction spécifiée, mais ne contient pas de « = ». Vous pouvez obtenir beaucoup de faux positifs (et potentiellement des faux négatifs) mais si vous ne disposez pas d'un analyseur statique, il est un bon endroit pour commencer.

Le programme « peluches » classique utilisé pour être très bavard sur les fonctions qui ont renvoyé une valeur qui a été ignoré. Le problème était, bon nombre de ces avertissements étaient indésirables - conduisant à un bruit excessif dans la sortie de la fibre (il ramassait des morceaux de peluches que vous l'avez voulu ignorer). C'est probablement pourquoi GCC ne dispose pas d'un avertissement standard pour cela.

L'autre question - le revers de la médaille - est « comment voulez-vous supprimer l'avertissement lorsque vous savez que vous ignorez le résultat mais vraiment ne se soucient pas ». Le scénario classique pour cela est:

if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
    signal(SIGHUP, sighandler);

Vous souciez le premier résultat de signal(); vous savez que la seconde sera SIG_IGN (puisque vous venez de définir à cela). Pour sortir des mises en garde, je l'utilise parfois une variante:

if ((old = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
    old = signal(SIGHUP, sighandler);

Cette attribue à old les deux fois. Vous pouvez suivre cela avec 'assert (ancien == SIG_IGN).

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