Domanda

Mi piacerebbe vedere tutti i luoghi nel mio codice (C ++), che il valore di ritorno disprezzo di una funzione. Come posso farlo - con gcc o strumento di analisi statica del codice

?

esempio di codice Bad:

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;
}

Si prega di notare che:

  • dovrebbe funzionare anche se la funzione e il suo uso sono nel file diversi
  • libero strumento di controllo statico
È stato utile?

Soluzione

Si vuole attributo warn_unused_result del 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;
}

Il tentativo di compilare il codice produce:

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

Si può vedere questo in uso nel kernel Linux ; hanno una macro __must_check che fa la stessa cosa; sembra che avete bisogno di GCC 3.4 o superiore per far funzionare tutto questo. Poi si scoprirà che la macro utilizzata nel file header del kernel:

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

Altri suggerimenti

Per quanto io sappia non esiste alcuna opzione GCC per dare questo avvertimento. Tuttavia, se siete interessati a funzioni specifiche, è possibile contrassegnarle con un attributo:

int fn() __attribute__((warn_unused_result));

che darebbe un avviso se il valore di ritorno di fn () non è stato utilizzato. Caveat: Non ho mai usato questa funzione me

.

È possibile utilizzare questo modello utile per farlo in fase di esecuzione.

Invece di restituire un codice di errore (ad esempio HRESULT) si restituisce un return_code , che afferma se va fuori del campo di applicazione, senza valore in fase di lettura. Non è uno strumento di analisi statica, ma è utile comunque.

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;
};

Per C ++ 17 la risposta a questa domanda cambiamenti dal momento che ora hanno la rel="noreferrer"> attributo. Coperto in [dcl.attr.nodiscard] :

  

Il nodiscard attributo token potrebbe essere applicato al dichiaratore-id in una dichiarazione di funzione o alla dichiarazione di una classe o enumerazione. Esse devono essere presentate al massimo una volta in ogni attributo-list e nessun attributo-argomento della clausola deve essere presente.

e

  

[Esempio:

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
     

- esempio fine]

Quindi modificare il vostro esempio ( vederla dal vivo ):

[[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;
}

Ora ottenere una diagnosi sia con gcc e Clang es.

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

Qualsiasi codice analisi statica (ad esempio PC-Lint ) dovrebbe essere in grado di dirvi che. Per PC-Lint, so che questo è il caso.

un analizzatore statico farà il lavoro per voi, ma se il vostro codice di base è più che banale si preparano a essere travolti; -)

Un analizzatore statico sarà la soluzione migliore qui. Usiamo Coverity qui, ma ci sono disponibili che è possibile utilizzare come pure strumenti gratuiti.

Se avete bisogno di una soluzione rapida-and-dirty e si dispone di un guscio in stile Linux a portata di mano, si può provare qualcosa di simile:

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

che troverà ogni riga che fa riferimento alla funzione specificata, ma non contiene un "=". È possibile ottenere un sacco di falsi positivi (e potenzialmente alcuni falsi negativi), ma se non si dispone di un analizzatore statico si tratta di un posto decente per iniziare.

Il programma classico 'lint' usato per essere molto volubile sulle funzioni che hanno restituito un valore che è stato ignorato. Il problema era che molti di questi avvertimenti sono stati indesiderati - che conduce al rumore eccessivo nell'output lint (che stava raccogliendo pezzi di lanugine che si voleva che ignorare). Questo è probabilmente il motivo per GCC non ha un avvertimento standard per esso.

L'altra questione - il rovescio della medaglia - è "come si fa a eliminare l'avviso quando si sa che si sta ignorando il risultato, ma in realtà non si cura". Lo scenario classico di ciò è:

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

Vi preoccupate per il primo risultato da signal(); si sa che il secondo sarà SIG_IGN (dal momento che solo imposta a quello). Per allontanarsi dalle avvertimenti, a volte utilizzare alcuni variante:

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

Questo assegna a old entrambe le volte. È possibile seguire che con 'assert (vecchio == SIG_IGN)'.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top