valores una todas tipos retornan que llamar lenguaje las funciones funcion ejemplos dev como c coding-style return-value lint

una - tipos de funciones en lenguaje c



Ignorando los valores de retorno en C (10)

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

int main(void) { printf("Hello world/n"); return 0; }

Últimamente, comencé a usar lint para el análisis de código estático. Una de las advertencias que recibo a veces es sobre 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 que la advertencia desaparezca, uno puede escribir

(void) foo();

Mi pregunta es, ¿cuál es la forma "correcta" de escribir código como este, debería continuar como siempre lo hice, ya que el compilador no se queja, o debería usar el vacío para mayor claridad, para que el otro mantenedor del código sepa que deliberadamente ignoré el valor de retorno.

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


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

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


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 hace, esa es una solución).

Solía ​​convertir a (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)

Férula divertida 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. Splint necesita una actualización con respecto a este problema.

Entonces, 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í:

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

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

La comparación 1==... es necesaria solo para evitar la tablilla advirtiendo que este condicional no es BOOL . A GCC no le puede importar menos. Dependiendo de la función, es posible que reciba una advertencia de cast . Hice una prueba ignorando un double con esta MACRO y estuvo bien, pero de alguna manera no estoy del todo convencido. Especialmente si la función devuelve un puntero o algo más complejo.

En este caso, también necesitarás:

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

Lo último: el {;} es necesario debido a la -Wempty-body vacío" (sugiere llaves alrededor del cuerpo vacío en una declaración "si").

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

Ejecutar el compilador no da advertencia o errores. 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

Ver también esta respuesta


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

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

Entonces en tu ejemplo, tendrías:

val = foo(); _unused(val);


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

Por lo tanto, debe conservar el (void) o desactivar el cheque para printf . Ahora tiene varias opciones para hacerlo de una manera legible. Utilizo para envolver la función dentro de una nueva función como por ejemplo

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

donde el elenco no tan bueno tiene lugar. Tal vez sea más práctico hacerlo usando una macro de preprocesador en este caso debido a los varargs ...


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

Con gcc 4.6, se está poniendo bastante complicado.

  • Casting to (void) ya no funciona.
  • Volver a escribir las funciones (especialmente variadic) es tedioso y torpe.
  • {ssize_t ignore; ignore=write(...);} {ssize_t ignore; ignore=write(...);} lanza otra advertencia (asignado-no-usado).
  • write(...)+1 arroja otra advertencia más (valor calculado no utilizado).

La única forma buena (aunque fea) de suprimirlos es convertir el valor devuelto en algo que el compilador acepte ignorar.

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

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


Por lo general, no hay demasiadas funciones cuyo valor desea ignorar. Splint , por ejemplo, permite agregar un comentario especial que lo haría saber, que un valor de retorno de una función específica podría ser ignorado. Desafortunadamente, esto en efecto desactiva 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 prototipo adicional a una función del sistema con un comentario en alguna parte.

Por cierto, por defecto Splint no se queja del valor de retorno de printf y de algunas otras funciones de libc que no se utilizan. Sin embargo, se puede activar un modo más estricto.

LINT 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 usando una 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. Luego, LINT reconoce que esta función devuelve un resultado que puede ignorarse; LINT no proporciona mensajes de error si se ignora el resultado.


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 /* ... */

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


Una manera un poco más "bella" 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 se puede extender a:

template<typename T> inline void ignore_result(T /* unused result */) {}


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