Ignorar los valores devueltos en C


Últimamente, empecé a usar lint para el análisis de código estático. Una de las advertencias que recibo a veces es con respecto a este tema. Digamos por ejemplo que tengo la siguiente función:

uint32_t foo( void );

Y digamos que deliberadamente ignoro el valor de retorno de la función. Para hacer desaparecer la advertencia, se puede escribir

(void) foo();

Mi pregunta es, ¿cuál es la forma "adecuada" de escribir código como este, debería continuar como siempre lo hice, ya que el compilador no se queja de ello, o debería use el void para mayor claridad, para que otros mantenedores de código sepan que deliberadamente ignoré el valor devuelto.

Cuando miro el código así ( con el vacío ), me parece bastante extraño...

Author: stdcall, 2012-08-09

10 answers

La forma común es simplemente llamar a foo(); sin lanzar en (void).

El que nunca ha ignorado el valor de retorno printf(), tire la primera piedra.

 51
Author: mouviciel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-09 17:24:31

Personalmente me gustan las advertencias "no utilizadas", pero en ocasiones hay casos en los que tengo que ignorarlas (por ejemplo, el write() al usuario, o fscanf(...,"%*s\n") o strtol() donde el valor devuelto no es importante y solo quiero el efecto secundario de [tal vez] mover el puntero del archivo.)

Con gcc 4.6, se está volviendo bastante complicado.

  • La fundición a (void) ya no funciona.
  • Reescribir funciones (especialmente variádicas) es tedioso y torpe.
  • {ssize_t ignore; ignore=write(...);} lanza otra advertencia (asignado-no-usado).
  • write(...)+1 lanza otra advertencia (valor computado-no-usado).

La única manera buena (aunque fea) de suprimir esto es convertir el valor devuelto en algo que el compilador está de acuerdo en que se puede ignorar.

Por ejemplo, (void)(write(...)+1).

Esto es aparentemente progreso. (Y +0 no funciona, POR cierto.)

 24
Author: dfsmith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-22 02:33:55

Una forma de hacer esto con los compiladores Clang y GCC es con un pragma:

    /* ... */

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result" 

    foo(); /* this specific unused-result warning gets ignored during compilation */

#pragma GCC diagnostic pop 

    /* ... */

El push-pop combination envuelve la directiva ignored para que las advertencias puedan activarse en cualquier parte del código. Debería ser más fácil para cualquiera que lea su código fuente en el futuro ver lo que hace este bloque de código.

 12
Author: Alex Reynolds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-11 00:12:48

Para que un comprobador de código estático sea útil, debe informar también de los valores de retorno ignorados, lo que puede conducir muy a menudo a errores difíciles de rastrear, o a la falta de manejo de errores.

Por lo que debe mantener el (void) o desactivar la comprobación de printf. Ahora tienes varias opciones para hacerlo de una manera legible. Uso para envolver la función dentro de una nueva función como por ejemplo

void printf_unchecked(const char* format, ...)

Donde tiene lugar el reparto no tan agradable. Tal vez sea más práctico hacerlo usando un macro preprocesador en este caso debido a los varargs...

 8
Author: jdehaan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-09 17:28:36

Una forma un poco más "hermosa" de indicar los resultados no utilizados sería esta:

/**
 * Wrapping your function call with ignore_result makes it more clear to
 * readers, compilers and linters that you are, in fact, ignoring the
 * function's return value on purpose.
 */
static inline void ignore_result(long long int unused_result) {
    (void) unused_result;
}

...

ignore_result(foo());

Con C++, esto puede extenderse a:

template<typename T>
inline void ignore_result(T /* unused result */) {}
 7
Author: mic_e,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-11 11:44:13

Me gusta compilar mis códigos con las banderas:

$gcc prog1.c -o prog1.x -Wall -Wextra -ansi -pedantic-errors -g -O0 -DDEBUG=1

Y para evitar -Wunused-result no me gusta la idea de agregar otra bandera: -Wno-unused-result (si lo haces, esa es una solución).

Solía usar (void) para algunas funciones (no printf u otras famosas, ya que los compiladores no advierten sobre ellas, solo las extrañas). Ahora lanzar a (void) ya no funciona (GCC 4.7.2)

Divertida férula aconseja:

Result returned by function call is not used. If this is intended,
can cast result to (void) to eliminate message. (Use -retvalother to
inhibit warning)

Pero esto ya no es una solución. Tablilla necesita una actualización en relación con este tema.

Por lo tanto, para deshacerse de la advertencia de una manera muy compatible, aquí hay una buena MACRO:

/** Turn off -Wunused-result for a specific function call */
#define igr(M) if(1==((int)M)){;}

Y llámalo así: {[26]]}

igr(PL_get_chars(t, &s, CVT_VARIABLE));

Es un aspecto limpio, y cualquier compilador eliminará el código. A continuación una imagen de mi editor preferido vi: ventana izquierda, no igr(); ventana central, usando igr(); ventana derecha, fuente.

introduzca la descripción de la imagen aquí

Puedes ver, es exactamente el mismo, un código completamente inocuo que permite a C hacer lo que gcc no permite: ignorar el código de devolución.

La comparación 1==... solo es necesaria para evitar la advertencia de tablilla de que este condicional es no BOOL. A GCC no le importa. Dependiendo de la función, puede recibir una advertencia cast. Hice una prueba ignorando un double con esta MACRO y fue bueno, pero de alguna manera no estoy completamente convencido. Especialmente si la función devuelve un puntero o algo más complejo.

En este caso también necesitará:

#define pigr(M) if(NULL==((void *)M)){;}

Última cosa: el {;} es necesario debido a la advertencia -Wempty-body (sugerir llaves alrededor del cuerpo vacío en una sentencia 'if').

Y (ahora lo último) el ; después de la llamada a la función no es (estrictamente) necesario, sino su buena práctica. Hace que sus líneas de código sean más homogéneas, todas terminan en un ;. (Se traduce como NOP mnemónico, y después de la optimización, desaparecer).


Ejecutar el compilador no da ninguna advertencia o error. Runing splint da:

$ splint ./teste.c -I/usr/lib/swi-prolog/include/ -strict-lib
Splint 3.1.2 --- 20 Feb 2009

Finished checking --- no warnings

Véase también este respuesta

 4
Author: Dr Beco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:49

Gnulib tiene esto: http://git.savannah.gnu.org/cgit/gnulib.git/tree/lib/ignore-value.h

/* Normally casting an expression to void discards its value, but GCC
   versions 3.4 and newer have __attribute__ ((__warn_unused_result__))
   which may cause unwanted diagnostics in that case.  Use __typeof__
   and __extension__ to work around the problem, if the workaround is
   known to be needed.  */
#if 3 < __GNUC__ + (4 <= __GNUC_MINOR__)
# define ignore_value(x) \
    (__extension__ ({ __typeof__ (x) __x = (x); (void) __x; }))
#else
# define ignore_value(x) ((void) (x))
#endif
 3
Author: Eric Blake,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-21 14:03:52

Normalmente no hay demasiadas funciones cuyo valor se quiera ignorar. Splint, por ejemplo, permite agregar un comentario especial que le haría saber, que un valor devuelto de una función específica podría ser ignorado. Desafortunadamente, esto en efecto deshabilita todas las advertencias de 'valor devuelto ignorado' relacionadas con esa función en particular.

Aquí hay un ejemplo del programa Splint-clean :

#include <stdio.h>

FILE /*@alt void@*/ *fopen(const char *path, const char *mode);

static int /*@alt void@*/ test(void)
{
   printf( "test called\n" );

   fopen( "test", "a" );

   return 0;
}

int main(void)
{  
   test();

   return 0;
}

La parte desagradable es que necesita agregar un adicional prototype a una función del sistema con un comentario en alguna parte.

Por cierto,por defecto Splint no se queja de que el valor de retorno de printf y de algunas otras funciones libc no estén en uso. Sin embargo, se puede activar un modo más estricto.

PELUSA permite algo similar, pero nunca lo he usado. Esto es lo que dice una documentación.

LINT le permite marcar funciones con valores de retorno opcionales mediante un directiva similar a las directivas #del preprocesador C.

#pragma optresult

Se puede colocar inmediatamente antes de la definición de una función que devuelve un resultado opcional. PELUSA entonces reconoce que esta función devuelve un resultado que puede ser ignorado; LINT no da error mensajes si el resultado es ignorado.

 1
Author: Maksim Skurydzin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-09 17:57:12

Otra solución sería utilizar realmente un valor. Luego podría eliminar la advertencia unused variable con una macro.

#define _unused(x) ((void)(x))

Entonces en tu ejemplo, tendrías:

val = foo();
_unused(val); 
 0
Author: xyz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-21 17:08:04

Es totalmente legal y aceptable escribir código que ignora el valor devuelto en algunos casos. El siguiente programa tiene muy pocas razones para comprobar el valor devuelto de printf().

int main(void) {
  printf("Hello world\n");
  return 0;
}
 -2
Author: Variable Length Coder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-09 17:20:55