Pregunta

Me gustaría ver a todos los lugares de mi código (C ++) que desconocen el valor de retorno de una función. ¿Cómo puedo hacerlo - con gcc o una herramienta de análisis de código estático

?

Mal ejemplo de código:

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

Tenga en cuenta que:

  • debería funcionar incluso si la función y su utilización aparecen en diferentes archivos
  • libre herramienta de comprobación estática
¿Fue útil?

Solución

¿Quieres atributo 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;
}

Tratando de compilar este código produce:

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

Esto se puede ver en uso en la kernel de Linux ; tienen una macro __must_check que hace lo mismo; Parece que necesitas GCC 3.4 o superior para que esto funcione. A continuación, usted encontrará que la macro se utiliza en los archivos de cabecera del kernel:

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

Otros consejos

Por lo que yo soy consciente de que no hay opción de GCC para dar esta advertencia. Sin embargo, si usted está interesado en funciones específicas, puede etiquetar con un atributo:

int fn() __attribute__((warn_unused_result));

lo que daría una advertencia si no se utilizó el valor de retorno de fn (). Advertencia: Nunca he utilizado esta característica mí

.

Puede utilizar esta plantilla práctica de hacerlo en tiempo de ejecución.

En lugar de devolver un código de error (por ejemplo HRESULT) devuelve un return_code , que afirma que si se sale del ámbito sin que se lea el valor. No es una herramienta de análisis estático, pero es útil, no obstante.

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

En C ++ 17 La respuesta a esta pregunta cambia ya que ahora tienen la rel="noreferrer"> atributo. Cubierto en [dcl.attr.nodiscard] :

  

El nodiscard atributo-token se puede aplicar a la declarador-id en una declaración de la función o de la declaración de una clase o enumeración. Será aparecer como máximo una vez en cada lista de atributos y ningún atributo-argumento-cláusula deberá estar presente.

y

  

[Ejemplo:

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
     

- ejemplo final]

Así que la modificación de su ejemplo ( verlo en directo ):

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

ahora obtenemos un diagnóstico tanto con gcc y sonido metálico por ejemplo.

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

Cualquier código de análisis estático (por ejemplo PC-Lint ) debe ser capaz de decirle eso. Para PC-Lint, sé que este es el caso.

un analizador estático va a hacer el trabajo por usted, pero si su base de código es más que trivial se preparan para ser abrumado; -)

Un analizador estático será su mejor opción aquí. Utilizamos Coverity aquí, pero hay herramientas gratuitas disponibles que se pueden utilizar también.

Si necesita una solución rápida y sucia, y tiene una concha de estilo Linux a mano, puede intentar algo como:

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

que encontrará cada línea que hace referencia a la función especificada pero no contiene un "=". Usted puede obtener una gran cantidad de falsos positivos (y, potencialmente, algunos falsos negativos), pero si usted no tiene un analizador estático es un lugar decente para empezar.

El clásico programa 'pelusa' solía ser muy voluble acerca de las funciones que devuelven un valor que fue ignorada. El problema era que muchas de esas advertencias eran no deseados - que conduce a un ruido excesivo en la salida de la pelusa (que estaba recogiendo trozos de pelusa que quería que ignoran). Esa es probablemente la razón por GCC no tiene una advertencia estándar para él.

La otra cuestión - el otro lado - es "¿cómo suprimir la advertencia cuando se sabe que está haciendo caso omiso del resultado, pero realmente no importa". El escenario clásico de esto es:

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

Usted se preocupa por el primer resultado de signal(); usted sabe que la segunda será SIG_IGN (ya que sólo se establece en eso). Para alejarse de las advertencias, a veces uso de alguna variante en:

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

Esto asigna a old en ambas ocasiones. Puede seguir que con 'assert (edad == SIG_IGN)'.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top